Make 'repo start' restartable upon failures

If `repo start foo` fails due to uncommitted and unmergeable changes
in a single project, we have switched half of the projects over to
the new target branches, but didn't on the one that failed to move.

This change improves the situation by doing three things differently:

- We keep going when we encounter an error, so other projects
  that can successfully switch still switch.

- We ignore projects whose current branch is already on the
  requested name; they are logically already setup.

- We checkout the branch if it already exists, rather than
  trying to recreate the branch.

Bug: REPO-22
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/project.py b/project.py
index 48ab847..06240b7 100644
--- a/project.py
+++ b/project.py
@@ -748,16 +748,31 @@
   def StartBranch(self, name):
     """Create a new branch off the manifest's revision.
     """
-    branch = self.GetBranch(name)
-    branch.remote = self.GetRemote(self.remote.name)
-    branch.merge = self.revision
+    try:
+      self.bare_git.rev_parse(R_HEADS + name)
+      exists = True
+    except GitError:
+      exists = False;
 
-    rev = branch.LocalMerge
-    cmd = ['checkout', '-b', branch.name, rev]
-    if GitCommand(self, cmd).Wait() == 0:
-      branch.Save()
+    if exists:
+      if name == self.CurrentBranch:
+        return True
+      else:
+        cmd = ['checkout', name, '--']
+        return GitCommand(self, cmd).Wait() == 0
+
     else:
-      raise GitError('%s checkout %s ' % (self.name, rev))
+      branch = self.GetBranch(name)
+      branch.remote = self.GetRemote(self.remote.name)
+      branch.merge = self.revision
+
+      rev = branch.LocalMerge
+      cmd = ['checkout', '-b', branch.name, rev]
+      if GitCommand(self, cmd).Wait() == 0:
+        branch.Save()
+        return True
+      else:
+        return False
 
   def CheckoutBranch(self, name):
     """Checkout a local topic branch.