<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -31,7 +31,7 @@ module Braid
     end
 
     def config
-      @config ||= Config.new
+      @config ||= load_and_migrate_config
     end
 
     private
@@ -55,6 +55,17 @@ module Braid
         end
       end
 
+      def load_and_migrate_config
+        config = Config.new
+        unless config.valid?
+          msg &quot;Configuration is outdated. Migrating.&quot;
+          bail_on_local_changes!
+          config.migrate!
+          git.commit(&quot;Upgrade .braids&quot;, &quot;-- .braids&quot;)
+        end
+        config
+      end
+
       def add_config_file
         git.add(CONFIG_FILE)
       end</diff>
      <filename>lib/braid/command.rb</filename>
    </modified>
    <modified>
      <diff>@@ -31,13 +31,6 @@ module Braid
       end
     end
 
-    def add(mirror)
-      @db.transaction do
-        raise PathAlreadyInUse, mirror.path if @db[mirror.path]
-        @db[mirror.path] = clean_attributes(mirror.attributes)
-      end
-    end
-
     def get(path)
       @db.transaction(true) do
         if attributes = @db[path.to_s.sub(/\/$/, '')]
@@ -52,6 +45,13 @@ module Braid
       mirror
     end
 
+    def add(mirror)
+      @db.transaction do
+        raise PathAlreadyInUse, mirror.path if @db[mirror.path]
+        write_mirror(mirror)
+      end
+    end
+
     def remove(mirror)
       @db.transaction do
         @db.delete(mirror.path)
@@ -61,14 +61,41 @@ module Braid
     def update(mirror)
       @db.transaction do
         raise MirrorDoesNotExist, mirror.path unless @db[mirror.path]
-        @db.delete(mirror)
-        @db[mirror.path] = clean_attributes(mirror.attributes)
+        @db.delete(mirror.path)
+        write_mirror(mirror)
+      end
+    end
+
+    def valid?
+      @db.transaction(true) do
+        !@db.roots.any? do |path|
+          @db[path][&quot;url&quot;].nil?
+        end
+      end
+    end
+
+    def migrate!
+      @db.transaction do
+        @db.roots.each do |path|
+          attributes = @db[path]
+          if attributes[&quot;local_branch&quot;]
+            attributes[&quot;url&quot;] = attributes.delete(&quot;remote&quot;)
+            attributes[&quot;remote&quot;] = attributes.delete(&quot;local_branch&quot;)
+            attributes[&quot;squashed&quot;] = attributes.delete(&quot;squash&quot;)
+            attributes[&quot;lock&quot;] = attributes[&quot;revision&quot;] # so far this has always been true
+          end
+          @db[path] = clean_attributes(attributes)
+        end
       end
     end
 
     private
+      def write_mirror(mirror)
+        @db[mirror.path] = clean_attributes(mirror.attributes)
+      end
+
       def clean_attributes(hash)
-        (hash = hash.dup).each { |k,v| hash.delete(k) if v.nil? }
+        hash.reject { |k,v| v.nil? }
       end
   end
 end</diff>
      <filename>lib/braid/config.rb</filename>
    </modified>
    <modified>
      <diff>@@ -13,7 +13,7 @@ module Braid
         &quot;cannot guess type: #{super}&quot;
       end
     end
-    class PathIsRequired &lt; BraidError
+    class PathRequired &lt; BraidError
       def message
         &quot;path is required&quot;
       end
@@ -40,7 +40,7 @@ module Braid
       end
 
       unless path = options[&quot;path&quot;] || extract_path_from_url(url)
-        raise PathIsRequired
+        raise PathRequired
       end
 
       if options[&quot;rails_plugin&quot;]
@@ -55,15 +55,6 @@ module Braid
       self.new(path, attributes)
     end
 
-    def locked?
-      # the question mark just looks nicer
-      !!lock
-    end
-
-    def squashed?
-      !!squashed
-    end
-
     def ==(comparison)
       path == comparison.path &amp;&amp; attributes == comparison.attributes
     end
@@ -73,6 +64,14 @@ module Braid
       attributes[&quot;type&quot;]
     end
 
+    def locked?
+      !!lock
+    end
+
+    def squashed?
+      !!squashed
+    end
+
     def merged?(commit)
       # tip from spearce in #git:
       # `test z$(git merge-base A B) = z$(git rev-parse --verify A)`
@@ -84,14 +83,10 @@ module Braid
       end
     end
 
-    def local_changes?
-      !diff.empty?
-    end
-
     def diff
-      remote_hash = git.rev_parse(base_revision)
+      remote_hash = git.rev_parse(&quot;#{base_revision}:&quot;)
       local_hash = git.tree_hash(path)
-      git.diff_tree(remote_hash, local_hash, path)
+      remote_hash != local_hash ? git.diff_tree(remote_hash, local_hash, path) : &quot;&quot;
     end
 
     def fetch
@@ -116,10 +111,36 @@ module Braid
       end
 
       def base_revision
-        revision &amp;&amp; unless type == &quot;svn&quot;
-          git.rev_parse(revision)
+        if revision
+          unless type == &quot;svn&quot;
+            git.rev_parse(revision)
+          else
+            git_svn.commit_hash(remote, revision)
+          end
         else
-          git_svn.commit_hash(remote, revision)
+          inferred_revision
+        end
+      end
+
+      def inferred_revision
+        time = list_revisions(&quot;-E --grep='^(Add|Update) mirror'&quot;, &quot;-1&quot;, &quot;HEAD&quot;, &quot;-- #{path}&quot;).first[0]
+        revs = list_revisions(&quot;--reverse&quot;, remote)
+        hash = nil
+        revs.each_with_index do |rev, idx|
+          if !revs[idx + 1] || revs[idx + 1][0] &gt; time
+            hash = revs[idx][1]
+            break
+          end
+        end
+        hash
+      end
+
+      def list_revisions(*args)
+        out = git.rev_list(&quot;--timestamp&quot;, *args)
+        out.split(&quot;\n&quot;).map do |line|
+          parts = line.split(' ', 2)
+          parts[0] = parts[0].to_i
+          parts
         end
       end
 </diff>
      <filename>lib/braid/mirror.rb</filename>
    </modified>
    <modified>
      <diff>@@ -110,8 +110,8 @@ module Braid
     end
 
     class Git &lt; Proxy
-      def commit(message)
-        status, out, err = exec(&quot;git commit -m #{message.inspect} --no-verify&quot;)
+      def commit(message, *args)
+        status, out, err = exec(&quot;git commit -m #{message.inspect} --no-verify #{args.join(' ')}&quot;)
 
         if status == 0
           true
@@ -219,10 +219,9 @@ module Braid
         out[2..-1]
       end
 
-      def apply(diff)
+      def apply(diff, *args)
         err = nil
-        # always uses index
-        status = Open4.popen4(&quot;git apply --index -&quot;) do |pid, stdin, stdout, stderr|
+        status = Open4.popen4(&quot;git apply --index --whitespace=nowarn #{args.join(' ')} -&quot;) do |pid, stdin, stdout, stderr|
           stdin.puts(diff)
           stdin.close
 
@@ -242,7 +241,7 @@ module Braid
       def self.command; &quot;git-svn&quot;; end
 
       def commit_hash(remote, revision)
-        status, out, err = invoke(:log, &quot;--show-commit --oneline&quot;, &quot;-r #{revision}&quot;, remote)
+        out = invoke(:log, &quot;--show-commit --oneline&quot;, &quot;-r #{revision}&quot;, remote)
         part = out.to_s.split(&quot; | &quot;)[1]
         raise UnknownRevision, &quot;r#{revision}&quot; unless part
         Git.instance.rev_parse(part) # FIXME ugly ugly ugly</diff>
      <filename>lib/braid/operations.rb</filename>
    </modified>
    <modified>
      <diff>@@ -52,7 +52,7 @@ describe &quot;Braid::Config, with one mirror&quot; do
   it &quot;should update the mirror with new params&quot; do
     @mirror.branch = &quot;other&quot;
     @config.update(@mirror)
-    @config.get(&quot;path&quot;).attributes.should == { &quot;url&quot; =&gt; &quot;url&quot;, &quot;branch&quot; =&gt; &quot;other&quot; }
+    @config.get(&quot;path&quot;).attributes.should == { &quot;branch&quot; =&gt; &quot;other&quot; }
   end
 
   it &quot;should raise when trying to update nonexistent mirror&quot; do</diff>
      <filename>test/config_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -43,32 +43,51 @@ end
 
 describe &quot;Braid::Mirror#diff&quot; do
   before(:each) do
-    @mirror = new_from_options(&quot;git://path&quot;)
-    git.stubs(:rev_parse)
-    git.stubs(:tree_hash)
+    @mirror = build_mirror(&quot;revision&quot; =&gt; 'a' * 40)
+    @mirror.stubs(:base_revision).returns(@mirror.revision) # bypass rev_parse
+  end
+
+  def set_hashes(remote_hash, local_hash)
+    git.expects(:rev_parse).with(&quot;#{@mirror.revision}:&quot;).returns(remote_hash)
+    git.expects(:tree_hash).with(@mirror.path).returns(local_hash)
   end
 
-  it &quot;should return true when the diff is not empty&quot; do
-    git.expects(:diff_tree).returns(&quot;diff --git a/path b/path\n&quot;)
-    @mirror.local_changes?.should == true
+  it &quot;should return an empty string when the hashes match&quot; do
+    set_hashes('b' * 40, 'b' * 40)
+    git.expects(:diff_tree).never
+    @mirror.diff.should == &quot;&quot;
   end
 
-  it &quot;should return false when the diff is empty&quot; do
-    git.expects(:diff_tree).returns(&quot;&quot;)
-    @mirror.local_changes?.should == false
+  it &quot;should generate a diff when the hashes do not match&quot; do
+    set_hashes('b' * 40, 'c' * 40)
+    diff = &quot;diff --git a/path b/path\n&quot;
+    git.expects(:diff_tree).with('b' * 40, 'c' * 40, @mirror.path).returns(diff)
+    @mirror.diff.should == diff
   end
 end
 
 describe &quot;Braid::Mirror#base_revision&quot; do
-  it &quot;should be nil when no revision is set&quot; do
-    @mirror = Braid::Mirror.new(&quot;path&quot;)
+  it &quot;should be inferred when no revision is set&quot; do
+    @mirror = build_mirror
     @mirror.revision.should.be.nil
-    @mirror.send(:base_revision).should.be.nil
+    @mirror.expects(:inferred_revision).returns('b' * 40)
+    @mirror.send(:base_revision).should == 'b' * 40
   end
 
   it &quot;should be the parsed hash for git mirrors&quot; do
-    @mirror = Braid::Mirror.new(&quot;path&quot;, &quot;revision&quot; =&gt; ('a' * 7))
-    git.expects(:rev_parse).returns('a' * 40)
+    @mirror = build_mirror(&quot;revision&quot; =&gt; 'a' * 7)
+    git.expects(:rev_parse).with('a' * 7).returns('a' * 40)
     @mirror.send(:base_revision).should == 'a' * 40
   end
 end
+
+describe &quot;Braid::Mirror#inferred_revision&quot; do
+  it &quot;should return the last commit before the most recent update&quot; do
+    @mirror = new_from_options(&quot;git://path&quot;)
+    @mirror.expects(:list_revisions).times(2).returns(
+      [[4, 'a' * 40], [2, 'b' * 40]],
+      [[1, 'c' * 40], [3, 'd' * 40], [5, 'e' * 40]]
+    )
+    @mirror.send(:inferred_revision).should == 'd' * 40
+  end
+end</diff>
      <filename>test/mirror_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -8,8 +8,8 @@ def new_from_options(url, options = {})
   @mirror = Braid::Mirror.new_from_options(url, options)
 end
 
-def build_mirror
-  Braid::Mirror.new(&quot;path&quot;, &quot;url&quot; =&gt; &quot;url&quot;)
+def build_mirror(options = {})
+  Braid::Mirror.new(&quot;path&quot;, options)
 end
 
 include Braid::Operations::VersionControl</diff>
      <filename>test/test_helper.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>c3baa80dfb6a29245f253c30b20fa23ad9465929</id>
    </parent>
  </parents>
  <author>
    <name>Norbert Crombach</name>
    <email>norbert.crombach@primetheory.org</email>
  </author>
  <url>http://github.com/evilchelu/braid/commit/3110de747a4b5dab499726c5a625568557247092</url>
  <id>3110de747a4b5dab499726c5a625568557247092</id>
  <committed-date>2008-08-19T08:40:38-07:00</committed-date>
  <authored-date>2008-07-15T06:22:13-07:00</authored-date>
  <message>Migrate config on load</message>
  <tree>56f5ff810c846b831e5b5790b0caa806ba3ff890</tree>
  <committer>
    <name>Norbert Crombach</name>
    <email>norbert.crombach@primetheory.org</email>
  </committer>
</commit>
