Merge "Use 'stat' package instead of literals for mkdir()"
diff --git a/color.py b/color.py
index 9200a29..33bc877 100644
--- a/color.py
+++ b/color.py
@@ -36,7 +36,8 @@
          'blink'  : 5,
          'reverse': 7}
 
-RESET = "\033[m"
+RESET = "\033[m"  # pylint: disable=W1401
+                  # backslash is not anomalous
 
 def is_color(s):
     return s in COLORS
@@ -51,7 +52,7 @@
 
     if attr >= 0 or fg >= 0 or bg >= 0:
       need_sep = False
-      code = "\033["
+      code = "\033["  #pylint: disable=W1401
 
       if attr >= 0:
         code += chr(ord('0') + attr)
diff --git a/command.py b/command.py
index d543e3a..babb833 100644
--- a/command.py
+++ b/command.py
@@ -60,32 +60,6 @@
     """
     raise NotImplementedError
 
-  def _ResetPathToProjectMap(self, projects):
-    self._by_path = dict((p.worktree, p) for p in projects)
-
-  def _UpdatePathToProjectMap(self, project):
-    self._by_path[project.worktree] = project
-
-  def _GetProjectByPath(self, path):
-    project = None
-    if os.path.exists(path):
-      oldpath = None
-      while path \
-        and path != oldpath \
-        and path != self.manifest.topdir:
-        try:
-          project = self._by_path[path]
-          break
-        except KeyError:
-          oldpath = path
-          path = os.path.dirname(path)
-    else:
-      try:
-        project = self._by_path[path]
-      except KeyError:
-        pass
-    return project
-
   def GetProjects(self, args, missing_ok=False):
     """A list of projects that match the arguments.
     """
@@ -97,41 +71,43 @@
     groups = mp.config.GetString('manifest.groups')
     if not groups:
       groups = 'all,-notdefault,platform-' + platform.system().lower()
-    groups = [x for x in re.split('[,\s]+', groups) if x]
+    groups = [x for x in re.split(r'[,\s]+', groups) if x]
 
     if not args:
-      all_projects_list = all_projects.values()
-      derived_projects = []
-      for project in all_projects_list:
-        if project.Registered:
-          # Do not search registered subproject for derived projects
-          # since its parent has been searched already
-          continue
-        derived_projects.extend(project.GetDerivedSubprojects())
-      all_projects_list.extend(derived_projects)
-      for project in all_projects_list:
+      for project in all_projects.values():
         if ((missing_ok or project.Exists) and
             project.MatchesGroups(groups)):
           result.append(project)
     else:
-      self._ResetPathToProjectMap(all_projects.values())
+      by_path = None
 
       for arg in args:
         project = all_projects.get(arg)
 
         if not project:
           path = os.path.abspath(arg).replace('\\', '/')
-          project = self._GetProjectByPath(path)
 
-          # If it's not a derived project, update path->project mapping and
-          # search again, as arg might actually point to a derived subproject.
-          if project and not project.Derived:
-            search_again = False
-            for subproject in project.GetDerivedSubprojects():
-              self._UpdatePathToProjectMap(subproject)
-              search_again = True
-            if search_again:
-              project = self._GetProjectByPath(path) or project
+          if not by_path:
+            by_path = dict()
+            for p in all_projects.values():
+              by_path[p.worktree] = p
+
+          if os.path.exists(path):
+            oldpath = None
+            while path \
+              and path != oldpath \
+              and path != self.manifest.topdir:
+              try:
+                project = by_path[path]
+                break
+              except KeyError:
+                oldpath = path
+                path = os.path.dirname(path)
+          else:
+            try:
+              project = by_path[path]
+            except KeyError:
+              pass
 
         if not project:
           raise NoSuchProjectError(arg)
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt
index a36af67..f499868 100644
--- a/docs/manifest-format.txt
+++ b/docs/manifest-format.txt
@@ -45,8 +45,7 @@
     <!ELEMENT manifest-server (EMPTY)>
     <!ATTLIST url              CDATA #REQUIRED>
   
-    <!ELEMENT project (annotation?,
-                       project*)>
+    <!ELEMENT project (annotation?)>
     <!ATTLIST project name     CDATA #REQUIRED>
     <!ATTLIST project path     CDATA #IMPLIED>
     <!ATTLIST project remote   IDREF #IMPLIED>
@@ -153,10 +152,7 @@
 
 One or more project elements may be specified.  Each element
 describes a single Git repository to be cloned into the repo
-client workspace.  You may specify Git-submodules by creating a
-nested project.  Git-submodules will be automatically
-recognized and inherit their parent's attributes, but those
-may be overridden by an explicitly specified project element.
+client workspace.
 
 Attribute `name`: A unique name for this project.  The project's
 name is appended onto its remote's fetch URL to generate the actual
@@ -167,8 +163,7 @@
 where ${remote_fetch} is the remote's fetch attribute and
 ${project_name} is the project's name attribute.  The suffix ".git"
 is always appended as repo assumes the upstream is a forest of
-bare Git repositories.  If the project has a parent element, its
-name will be prefixed by the parent's.
+bare Git repositories.
 
 The project name must match the name Gerrit knows, if Gerrit is
 being used for code reviews.
@@ -176,8 +171,6 @@
 Attribute `path`: An optional path relative to the top directory
 of the repo client where the Git working directory for this project
 should be placed.  If not supplied the project name is used.
-If the project has a parent element, its path will be prefixed
-by the parent's.
 
 Attribute `remote`: Name of a previously defined remote element.
 If not supplied the remote given by the default element is used.
@@ -197,8 +190,6 @@
 definition is implicitly in the following manifest groups:
 default, name:monkeys, and path:barrel-of.  If you place a project in the
 group "notdefault", it will not be automatically downloaded by repo.
-If the project has a parent element, the `name` and `path` here
-are the prefixed ones.
 
 Element annotation
 ------------------
diff --git a/git_command.py b/git_command.py
index a40e6c0..39f795f 100644
--- a/git_command.py
+++ b/git_command.py
@@ -132,15 +132,15 @@
                gitdir = None):
     env = os.environ.copy()
 
-    for e in [REPO_TRACE,
+    for key in [REPO_TRACE,
               GIT_DIR,
               'GIT_ALTERNATE_OBJECT_DIRECTORIES',
               'GIT_OBJECT_DIRECTORY',
               'GIT_WORK_TREE',
               'GIT_GRAFT_FILE',
               'GIT_INDEX_FILE']:
-      if e in env:
-        del env[e]
+      if key in env:
+        del env[key]
 
     if disable_editor:
       _setenv(env, 'GIT_EDITOR', ':')
diff --git a/git_config.py b/git_config.py
index ae28855..d6510aa 100644
--- a/git_config.py
+++ b/git_config.py
@@ -35,7 +35,7 @@
 
 R_HEADS = 'refs/heads/'
 R_TAGS  = 'refs/tags/'
-ID_RE = re.compile('^[0-9a-f]{40}$')
+ID_RE = re.compile(r'^[0-9a-f]{40}$')
 
 REVIEW_CACHE = dict()
 
@@ -288,7 +288,8 @@
     d = self._do('--null', '--list')
     if d is None:
       return c
-    for line in d.rstrip('\0').split('\0'):
+    for line in d.rstrip('\0').split('\0'):  # pylint: disable=W1401
+                                             # Backslash is not anomalous
       if '\n' in line:
           key, val = line.split('\n', 1)
       else:
diff --git a/git_refs.py b/git_refs.py
index 18c9230..cfeffba 100644
--- a/git_refs.py
+++ b/git_refs.py
@@ -138,14 +138,14 @@
   def _ReadLoose1(self, path, name):
     try:
       fd = open(path, 'rb')
-    except:
+    except IOError:
       return
 
     try:
       try:
         mtime = os.path.getmtime(path)
         ref_id = fd.readline()
-      except:
+      except (IOError, OSError):
         return
     finally:
       fd.close()
diff --git a/main.py b/main.py
index d993ee4..7a09c6b 100755
--- a/main.py
+++ b/main.py
@@ -23,10 +23,10 @@
 del magic
 
 import getpass
+import imp
 import netrc
 import optparse
 import os
-import re
 import sys
 import time
 import urllib2
@@ -167,16 +167,15 @@
 def _MyWrapperPath():
   return os.path.join(os.path.dirname(__file__), 'repo')
 
+_wrapper_module = None
+def WrapperModule():
+  global _wrapper_module
+  if not _wrapper_module:
+    _wrapper_module = imp.load_source('wrapper', _MyWrapperPath())
+  return _wrapper_module
+
 def _CurrentWrapperVersion():
-  VERSION = None
-  pat = re.compile(r'^VERSION *=')
-  fd = open(_MyWrapperPath())
-  for line in fd:
-    if pat.match(line):
-      fd.close()
-      exec line
-      return VERSION
-  raise NameError, 'No VERSION in repo script'
+  return WrapperModule().VERSION
 
 def _CheckWrapperVersion(ver, repo_path):
   if not repo_path:
diff --git a/manifest_xml.py b/manifest_xml.py
index 11e4ee5..cdee87a 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -180,25 +180,20 @@
       root.appendChild(e)
       root.appendChild(doc.createTextNode(''))
 
-    def output_projects(parent, parent_node, projects):
-      for p in projects:
-        output_project(parent, parent_node, self.projects[p])
+    sort_projects = list(self.projects.keys())
+    sort_projects.sort()
 
-    def output_project(parent, parent_node, p):
+    for p in sort_projects:
+      p = self.projects[p]
+
       if not p.MatchesGroups(groups):
-        return
-
-      name = p.name
-      relpath = p.relpath
-      if parent:
-        name = self._UnjoinName(parent.name, name)
-        relpath = self._UnjoinRelpath(parent.relpath, relpath)
+        continue
 
       e = doc.createElement('project')
-      parent_node.appendChild(e)
-      e.setAttribute('name', name)
-      if relpath != name:
-        e.setAttribute('path', relpath)
+      root.appendChild(e)
+      e.setAttribute('name', p.name)
+      if p.relpath != p.name:
+        e.setAttribute('path', p.relpath)
       if not d.remote or p.remote.name != d.remote.name:
         e.setAttribute('remote', p.remote.name)
       if peg_rev:
@@ -236,16 +231,6 @@
       if p.sync_c:
         e.setAttribute('sync-c', 'true')
 
-      if p.subprojects:
-        sort_projects = [subp.name for subp in p.subprojects]
-        sort_projects.sort()
-        output_projects(p, e, sort_projects)
-
-    sort_projects = [key for key in self.projects.keys()
-                     if not self.projects[key].parent]
-    sort_projects.sort()
-    output_projects(None, root, sort_projects)
-
     if self._repo_hooks_project:
       root.appendChild(doc.createTextNode(''))
       e = doc.createElement('repo-hooks')
@@ -398,15 +383,11 @@
     for node in itertools.chain(*node_list):
       if node.nodeName == 'project':
         project = self._ParseProject(node)
-        def recursively_add_projects(project):
-          if self._projects.get(project.name):
-            raise ManifestParseError(
-                'duplicate project %s in %s' %
-                (project.name, self.manifestFile))
-          self._projects[project.name] = project
-          for subproject in project.subprojects:
-            recursively_add_projects(subproject)
-        recursively_add_projects(project)
+        if self._projects.get(project.name):
+          raise ManifestParseError(
+              'duplicate project %s in %s' %
+              (project.name, self.manifestFile))
+        self._projects[project.name] = project
       if node.nodeName == 'repo-hooks':
         # Get the name of the project and the (space-separated) list of enabled.
         repo_hooks_project = self._reqatt(node, 'in-project')
@@ -556,19 +537,11 @@
 
     return '\n'.join(cleanLines)
 
-  def _JoinName(self, parent_name, name):
-    return os.path.join(parent_name, name)
-
-  def _UnjoinName(self, parent_name, name):
-    return os.path.relpath(name, parent_name)
-
-  def _ParseProject(self, node, parent = None):
+  def _ParseProject(self, node):
     """
     reads a <project> element from the manifest file
     """
     name = self._reqatt(node, 'name')
-    if parent:
-      name = self._JoinName(parent.name, name)
 
     remote = self._get_remote(node)
     if remote is None:
@@ -611,68 +584,39 @@
     groups = ''
     if node.hasAttribute('groups'):
       groups = node.getAttribute('groups')
-    groups = [x for x in re.split('[,\s]+', groups) if x]
+    groups = [x for x in re.split(r'[,\s]+', groups) if x]
 
-    if parent is None:
-      relpath, worktree, gitdir = self.GetProjectPaths(name, path)
-    else:
-      relpath, worktree, gitdir = self.GetSubprojectPaths(parent, path)
-
-    default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath]
+    default_groups = ['all', 'name:%s' % name, 'path:%s' % path]
     groups.extend(set(default_groups).difference(groups))
 
+    if self.IsMirror:
+      worktree = None
+      gitdir = os.path.join(self.topdir, '%s.git' % name)
+    else:
+      worktree = os.path.join(self.topdir, path).replace('\\', '/')
+      gitdir = os.path.join(self.repodir, 'projects/%s.git' % path)
+
     project = Project(manifest = self,
                       name = name,
                       remote = remote.ToRemoteSpec(name),
                       gitdir = gitdir,
                       worktree = worktree,
-                      relpath = relpath,
+                      relpath = path,
                       revisionExpr = revisionExpr,
                       revisionId = None,
                       rebase = rebase,
                       groups = groups,
                       sync_c = sync_c,
-                      upstream = upstream,
-                      parent = parent)
+                      upstream = upstream)
 
     for n in node.childNodes:
       if n.nodeName == 'copyfile':
         self._ParseCopyFile(project, n)
       if n.nodeName == 'annotation':
         self._ParseAnnotation(project, n)
-      if n.nodeName == 'project':
-        project.subprojects.append(self._ParseProject(n, parent = project))
 
     return project
 
-  def GetProjectPaths(self, name, path):
-    relpath = path
-    if self.IsMirror:
-      worktree = None
-      gitdir = os.path.join(self.topdir, '%s.git' % name)
-    else:
-      worktree = os.path.join(self.topdir, path).replace('\\', '/')
-      gitdir = os.path.join(self.repodir, 'projects', '%s.git' % path)
-    return relpath, worktree, gitdir
-
-  def GetSubprojectName(self, parent, submodule_path):
-    return os.path.join(parent.name, submodule_path)
-
-  def _JoinRelpath(self, parent_relpath, relpath):
-    return os.path.join(parent_relpath, relpath)
-
-  def _UnjoinRelpath(self, parent_relpath, relpath):
-    return os.path.relpath(relpath, parent_relpath)
-
-  def GetSubprojectPaths(self, parent, path):
-    relpath = self._JoinRelpath(parent.relpath, path)
-    gitdir = os.path.join(parent.gitdir, 'subprojects', '%s.git' % path)
-    if self.IsMirror:
-      worktree = None
-    else:
-      worktree = os.path.join(parent.worktree, path).replace('\\', '/')
-    return relpath, worktree, gitdir
-
   def _ParseCopyFile(self, project, node):
     src = self._reqatt(node, 'src')
     dest = self._reqatt(node, 'dest')
diff --git a/project.py b/project.py
index c5ee50f..cdb4ecf 100644
--- a/project.py
+++ b/project.py
@@ -22,11 +22,10 @@
 import stat
 import subprocess
 import sys
-import tempfile
 import time
 
 from color import Coloring
-from git_command import GitCommand
+from git_command import GitCommand, git_require
 from git_config import GitConfig, IsId, GetSchemeFromUrl, ID_RE
 from error import GitError, HookError, UploadError
 from error import ManifestInvalidRevisionError
@@ -485,28 +484,7 @@
                rebase = True,
                groups = None,
                sync_c = False,
-               upstream = None,
-               parent = None,
-               is_derived = False):
-    """Init a Project object.
-
-    Args:
-      manifest: The XmlManifest object.
-      name: The `name` attribute of manifest.xml's project element.
-      remote: RemoteSpec object specifying its remote's properties.
-      gitdir: Absolute path of git directory.
-      worktree: Absolute path of git working tree.
-      relpath: Relative path of git working tree to repo's top directory.
-      revisionExpr: The `revision` attribute of manifest.xml's project element.
-      revisionId: git commit id for checking out.
-      rebase: The `rebase` attribute of manifest.xml's project element.
-      groups: The `groups` attribute of manifest.xml's project element.
-      sync_c: The `sync-c` attribute of manifest.xml's project element.
-      upstream: The `upstream` attribute of manifest.xml's project element.
-      parent: The parent Project object.
-      is_derived: False if the project was explicitly defined in the manifest;
-                  True if the project is a discovered submodule.
-    """
+               upstream = None):
     self.manifest = manifest
     self.name = name
     self.remote = remote
@@ -529,9 +507,6 @@
     self.groups = groups
     self.sync_c = sync_c
     self.upstream = upstream
-    self.parent = parent
-    self.is_derived = is_derived
-    self.subprojects = []
 
     self.snapshots = {}
     self.copyfiles = []
@@ -552,14 +527,6 @@
     self.enabled_repo_hooks = []
 
   @property
-  def Registered(self):
-    return self.parent and not self.is_derived
-
-  @property
-  def Derived(self):
-    return self.is_derived
-
-  @property
   def Exists(self):
     return os.path.isdir(self.gitdir)
 
@@ -1045,6 +1012,10 @@
     self.CleanPublishedCache(all_refs)
     revid = self.GetRevisionId(all_refs)
 
+    def _doff():
+      self._FastForward(revid)
+      self._CopyFiles()
+
     self._InitWorkTree()
     head = self.work_git.GetHead()
     if head.startswith(R_HEADS):
@@ -1123,9 +1094,6 @@
         # All published commits are merged, and thus we are a
         # strict subset.  We can fast-forward safely.
         #
-        def _doff():
-          self._FastForward(revid)
-          self._CopyFiles()
         syncbuf.later1(self, _doff)
         return
 
@@ -1188,9 +1156,6 @@
         syncbuf.fail(self, e)
         return
     else:
-      def _doff():
-        self._FastForward(revid)
-        self._CopyFiles()
       syncbuf.later1(self, _doff)
 
   def AddCopyFile(self, src, dest, absdest):
@@ -1403,150 +1368,6 @@
     return kept
 
 
-## Submodule Management ##
-
-  def GetRegisteredSubprojects(self):
-    result = []
-    def rec(subprojects):
-      if not subprojects:
-        return
-      result.extend(subprojects)
-      for p in subprojects:
-        rec(p.subprojects)
-    rec(self.subprojects)
-    return result
-
-  def _GetSubmodules(self):
-    # Unfortunately we cannot call `git submodule status --recursive` here
-    # because the working tree might not exist yet, and it cannot be used
-    # without a working tree in its current implementation.
-
-    def get_submodules(gitdir, rev):
-      # Parse .gitmodules for submodule sub_paths and sub_urls
-      sub_paths, sub_urls = parse_gitmodules(gitdir, rev)
-      if not sub_paths:
-        return []
-      # Run `git ls-tree` to read SHAs of submodule object, which happen to be
-      # revision of submodule repository
-      sub_revs = git_ls_tree(gitdir, rev, sub_paths)
-      submodules = []
-      for sub_path, sub_url in zip(sub_paths, sub_urls):
-        try:
-          sub_rev = sub_revs[sub_path]
-        except KeyError:
-          # Ignore non-exist submodules
-          continue
-        submodules.append((sub_rev, sub_path, sub_url))
-      return submodules
-
-    re_path = re.compile(r'submodule.(\w+).path')
-    re_url = re.compile(r'submodule.(\w+).url')
-    def parse_gitmodules(gitdir, rev):
-      cmd = ['cat-file', 'blob', '%s:.gitmodules' % rev]
-      try:
-        p = GitCommand(None, cmd, capture_stdout = True, capture_stderr = True,
-                       bare = True, gitdir = gitdir)
-      except GitError:
-        return [], []
-      if p.Wait() != 0:
-        return [], []
-
-      gitmodules_lines = []
-      fd, temp_gitmodules_path = tempfile.mkstemp()
-      try:
-        os.write(fd, p.stdout)
-        os.close(fd)
-        cmd = ['config', '--file', temp_gitmodules_path, '--list']
-        p = GitCommand(None, cmd, capture_stdout = True, capture_stderr = True,
-                       bare = True, gitdir = gitdir)
-        if p.Wait() != 0:
-          return [], []
-        gitmodules_lines = p.stdout.split('\n')
-      except GitError:
-        return [], []
-      finally:
-        os.remove(temp_gitmodules_path)
-
-      names = set()
-      paths = {}
-      urls = {}
-      for line in gitmodules_lines:
-        if not line:
-          continue
-        key, value = line.split('=')
-        m = re_path.match(key)
-        if m:
-          names.add(m.group(1))
-          paths[m.group(1)] = value
-          continue
-        m = re_url.match(key)
-        if m:
-          names.add(m.group(1))
-          urls[m.group(1)] = value
-          continue
-      names = sorted(names)
-      return [paths[name] for name in names], [urls[name] for name in names]
-
-    def git_ls_tree(gitdir, rev, paths):
-      cmd = ['ls-tree', rev, '--']
-      cmd.extend(paths)
-      try:
-        p = GitCommand(None, cmd, capture_stdout = True, capture_stderr = True,
-                       bare = True, gitdir = gitdir)
-      except GitError:
-        return []
-      if p.Wait() != 0:
-        return []
-      objects = {}
-      for line in p.stdout.split('\n'):
-        if not line.strip():
-          continue
-        object_rev, object_path = line.split()[2:4]
-        objects[object_path] = object_rev
-      return objects
-
-    try:
-      rev = self.GetRevisionId()
-    except GitError:
-      return []
-    return get_submodules(self.gitdir, rev)
-
-  def GetDerivedSubprojects(self):
-    result = []
-    if not self.Exists:
-      # If git repo does not exist yet, querying its submodules will
-      # mess up its states; so return here.
-      return result
-    for rev, path, url in self._GetSubmodules():
-      name = self.manifest.GetSubprojectName(self, path)
-      project = self.manifest.projects.get(name)
-      if project and project.Registered:
-        # If it has been registered, skip it because we are searching
-        # derived subprojects, but search for its derived subprojects.
-        result.extend(project.GetDerivedSubprojects())
-        continue
-      relpath, worktree, gitdir = self.manifest.GetSubprojectPaths(self, path)
-      remote = RemoteSpec(self.remote.name,
-                          url = url,
-                          review = self.remote.review)
-      subproject = Project(manifest = self.manifest,
-                           name = name,
-                           remote = remote,
-                           gitdir = gitdir,
-                           worktree = worktree,
-                           relpath = relpath,
-                           revisionExpr = self.revisionExpr,
-                           revisionId = rev,
-                           rebase = self.rebase,
-                           groups = self.groups,
-                           sync_c = self.sync_c,
-                           parent = self,
-                           is_derived = True)
-      result.append(subproject)
-      result.extend(subproject.GetDerivedSubprojects())
-    return result
-
-
 ## Direct Git Commands ##
 
   def _RemoteFetch(self, name=None,
@@ -2013,7 +1834,8 @@
       if p.Wait() == 0:
         out = p.stdout
         if out:
-          return out[:-1].split("\0")
+          return out[:-1].split('\0')  # pylint: disable=W1401
+                                       # Backslash is not anomalous
       return []
 
     def DiffZ(self, name, *args):
@@ -2029,7 +1851,7 @@
         out = p.process.stdout.read()
         r = {}
         if out:
-          out = iter(out[:-1].split('\0'))
+          out = iter(out[:-1].split('\0'))  # pylint: disable=W1401
           while out:
             try:
               info = out.next()
@@ -2165,6 +1987,9 @@
           raise TypeError('%s() got an unexpected keyword argument %r'
                           % (name, k))
         if config is not None:
+          if not git_require((1, 7, 2)):
+            raise ValueError('cannot set config on command line for %s()'
+                             % name)
           for k, v in config.iteritems():
             cmdv.append('-c')
             cmdv.append('%s=%s' % (k, v))
diff --git a/repo b/repo
index fdb852e..9643a22 100755
--- a/repo
+++ b/repo
@@ -28,10 +28,10 @@
 del magic
 
 # increment this whenever we make important changes to this script
-VERSION = (1, 17)
+VERSION = (1, 19)
 
 # increment this if the MAINTAINER_KEYS block is modified
-KEYRING_VERSION = (1,0)
+KEYRING_VERSION = (1,1)
 MAINTAINER_KEYS = """
 
      Repo Maintainer <repo@android.kernel.org>
@@ -75,12 +75,44 @@
 TACbBS+Up3RpfYVfd63c1cDdlru13pQAn3NQy/SN858MkxN+zym86UBgOad2
 =CMiZ
 -----END PGP PUBLIC KEY BLOCK-----
+
+     Conley Owens <cco3@android.com>
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.11 (GNU/Linux)
+
+mQENBFBiLPwBCACvISTASOgFXwADw2GYRH2I2z9RvYkYoZ6ThTTNlMXbbYYKO2Wo
+a9LQDNW0TbCEekg5UKk0FD13XOdWaqUt4Gtuvq9c43GRSjMO6NXH+0BjcQ8vUtY2
+/W4CYUevwdo4nQ1+1zsOCu1XYe/CReXq0fdugv3hgmRmh3sz1soo37Q44W2frxxg
+U7Rz3Da4FjgAL0RQ8qndD+LwRHXTY7H7wYM8V/3cYFZV7pSodd75q3MAXYQLf0ZV
+QR1XATu5l1QnXrxgHvz7MmDwb1D+jX3YPKnZveaukigQ6hDHdiVcePBiGXmk8LZC
+2jQkdXeF7Su1ZYpr2nnEHLJ6vOLcCpPGb8gDABEBAAG0H0NvbmxleSBPd2VucyA8
+Y2NvM0BhbmRyb2lkLmNvbT6JATgEEwECACIFAlBiLPwCGwMGCwkIBwMCBhUIAgkK
+CwQWAgMBAh4BAheAAAoJEBkmlFUziHGkHVkH/2Hks2Cif5i2xPtv2IFZcjL42joU
+T7lO5XFqUYS9ZNHpGa/V0eiPt7rHoO16glR83NZtwlrq2cSN89i9HfOhMYV/qLu8
+fLCHcV2muw+yCB5s5bxnI5UkToiNZyBNqFkcOt/Kbj9Hpy68A1kmc6myVEaUYebq
+2Chx/f3xuEthan099t746v1K+/6SvQGDNctHuaMr9cWdxZtHjdRf31SQRc99Phe5
+w+ZGR/ebxNDKRK9mKgZT8wVFHlXerJsRqWIqtx1fsW1UgLgbpcpe2MChm6B5wTu0
+s1ltzox3l4q71FyRRPUJxXyvGkDLZWpK7EpiHSCOYq/KP3HkKeXU3xqHpcG5AQ0E
+UGIs/AEIAKzO/7lO9cB6dshmZYo8Vy/b7aGicThE+ChcDSfhvyOXVdEM2GKAjsR+
+rlBWbTFX3It301p2HwZPFEi9nEvJxVlqqBiW0bPmNMkDRR55l2vbWg35wwkg6RyE
+Bc5/TQjhXI2w8IvlimoGoUff4t3JmMOnWrnKSvL+5iuRj12p9WmanCHzw3Ee7ztf
+/aU/q+FTpr3DLerb6S8xbv86ySgnJT6o5CyL2DCWRtnYQyGVi0ZmLzEouAYiO0hs
+z0AAu28Mj+12g2WwePRz6gfM9rHtI37ylYW3oT/9M9mO9ei/Bc/1D7Dz6qNV+0vg
+uSVJxM2Bl6GalHPZLhHntFEdIA6EdoUAEQEAAYkBHwQYAQIACQUCUGIs/AIbDAAK
+CRAZJpRVM4hxpNfkB/0W/hP5WK/NETXBlWXXW7JPaWO2c5kGwD0lnj5RRmridyo1
+vbm5PdM91jOsDQYqRu6YOoYBnDnEhB2wL2bPh34HWwwrA+LwB8hlcAV2z1bdwyfl
+3R823fReKN3QcvLHzmvZPrF4Rk97M9UIyKS0RtnfTWykRgDWHIsrtQPoNwsXrWoT
+9LrM2v+1+9mp3vuXnE473/NHxmiWEQH9Ez+O/mOxQ7rSOlqGRiKq/IBZCfioJOtV
+fTQeIu/yASZnsLBqr6SJEGwYBoWcyjG++k4fyw8ocOAo4uGDYbxgN7yYfNQ0OH7o
+V6pfUgqKLWa/aK7/N1ZHnPdFLD8Xt0Dmy4BPwrKC
+=O7am
+-----END PGP PUBLIC KEY BLOCK-----
 """
 
 GIT = 'git'                     # our git command
-MIN_GIT_VERSION = (1, 5, 4)     # minimum supported git version
+MIN_GIT_VERSION = (1, 7, 2)     # minimum supported git version
 repodir = '.repo'               # name of repo's private directory
-S_repo = 'repo'                 # special repo reposiory
+S_repo = 'repo'                 # special repo repository
 S_manifests = 'manifests'       # special manifest repository
 REPO_MAIN = S_repo + '/main.py' # main script
 
@@ -131,7 +163,7 @@
                  metavar='GROUP')
 group.add_option('-p', '--platform',
                  dest='platform', default="auto",
-                 help='restrict manifest projects to ones with a specified'
+                 help='restrict manifest projects to ones with a specified '
                       'platform group [auto|all|none|linux|darwin|...]',
                  metavar='PLATFORM')
 
@@ -197,8 +229,8 @@
 
   _CheckGitVersion()
   try:
-    if _NeedSetupGnuPG():
-      can_verify = _SetupGnuPG(opt.quiet)
+    if NeedSetupGnuPG():
+      can_verify = SetupGnuPG(opt.quiet)
     else:
       can_verify = True
 
@@ -247,7 +279,7 @@
     raise CloneFailure()
 
 
-def _NeedSetupGnuPG():
+def NeedSetupGnuPG():
   if not os.path.isdir(home_dot_repo):
     return True
 
@@ -265,7 +297,7 @@
   return False
 
 
-def _SetupGnuPG(quiet):
+def SetupGnuPG(quiet):
   if not os.path.isdir(home_dot_repo):
     try:
       os.mkdir(home_dot_repo)
diff --git a/subcmds/grep.py b/subcmds/grep.py
index 0dc8f9f..b067629 100644
--- a/subcmds/grep.py
+++ b/subcmds/grep.py
@@ -51,7 +51,7 @@
 
 Look for a line that has '#define' and either 'MAX_PATH or 'PATH_MAX':
 
-  repo grep -e '#define' --and -\( -e MAX_PATH -e PATH_MAX \)
+  repo grep -e '#define' --and -\\( -e MAX_PATH -e PATH_MAX \\)
 
 Look for a line that has 'NODE' or 'Unexpected' in files that
 contain a line that matches both expressions:
diff --git a/subcmds/init.py b/subcmds/init.py
index b6b9807..48df9e8 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -147,7 +147,7 @@
       r.ResetFetch()
       r.Save()
 
-    groups = re.split('[,\s]+', opt.groups)
+    groups = re.split(r'[,\s]+', opt.groups)
     all_platforms = ['linux', 'darwin']
     platformize = lambda x: 'platform-' + x
     if opt.platform == 'auto':
@@ -313,6 +313,21 @@
       # We store the depth in the main manifest project.
       self.manifest.manifestProject.config.SetString('repo.depth', depth)
 
+  def _DisplayResult(self):
+    if self.manifest.IsMirror:
+      init_type = 'mirror '
+    else:
+      init_type = ''
+
+    print ''
+    print 'repo %shas been initialized in %s' % (init_type, self.manifest.topdir)
+
+    current_dir = os.getcwd()
+    if current_dir != self.manifest.topdir:
+      print 'If this is not the directory in which you want to initialize repo, please run:'
+      print '   rm -r %s/.repo' % self.manifest.topdir
+      print 'and try again.'
+
   def Execute(self, opt, args):
     git_require(MIN_GIT_VERSION, fail=True)
 
@@ -329,10 +344,4 @@
 
     self._ConfigureDepth(opt)
 
-    if self.manifest.IsMirror:
-      init_type = 'mirror '
-    else:
-      init_type = ''
-
-    print ''
-    print 'repo %sinitialized in %s' % (init_type, self.manifest.topdir)
+    self._DisplayResult()
diff --git a/subcmds/sync.py b/subcmds/sync.py
index a4ca344..15f69f7 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -44,8 +44,9 @@
 except ImportError:
   multiprocessing = None
 
-from git_command import GIT
+from git_command import GIT, git_require
 from git_refs import R_HEADS, HEAD
+from main import WrapperModule
 from project import Project
 from project import RemoteSpec
 from command import Command, MirrorSafeCommand
@@ -309,7 +310,8 @@
     return fetched
 
   def _GCProjects(self, projects):
-    if multiprocessing:
+    has_dash_c = git_require((1, 7, 2))
+    if multiprocessing and has_dash_c:
       cpu_count = multiprocessing.cpu_count()
     else:
       cpu_count = 1
@@ -537,7 +539,7 @@
     mp.PreSync()
 
     if opt.repo_upgraded:
-      _PostRepoUpgrade(self.manifest)
+      _PostRepoUpgrade(self.manifest, quiet=opt.quiet)
 
     if not opt.local_only:
       mp.Sync_NetworkHalf(quiet=opt.quiet,
@@ -562,31 +564,12 @@
       to_fetch.extend(all_projects)
       to_fetch.sort(key=self._fetch_times.Get, reverse=True)
 
-      fetched = self._Fetch(to_fetch, opt)
+      self._Fetch(to_fetch, opt)
       _PostRepoFetch(rp, opt.no_repo_verify)
       if opt.network_only:
         # bail out now; the rest touches the working tree
         return
 
-      # Iteratively fetch missing and/or nested unregistered submodules
-      previously_missing_set = set()
-      while True:
-        self.manifest._Unload()
-        all_projects = self.GetProjects(args, missing_ok=True)
-        missing = []
-        for project in all_projects:
-          if project.gitdir not in fetched:
-            missing.append(project)
-        if not missing:
-          break
-        # Stop us from non-stopped fetching actually-missing repos: If set of
-        # missing repos has not been changed from last fetch, we break.
-        missing_set = set(p.name for p in missing)
-        if previously_missing_set == missing_set:
-          break
-        previously_missing_set = missing_set
-        fetched.update(self._Fetch(missing, opt))
-
     if self.manifest.IsMirror:
       # bail out now, we have no working tree
       return
@@ -611,7 +594,10 @@
     if self.manifest.notice:
       print self.manifest.notice
 
-def _PostRepoUpgrade(manifest):
+def _PostRepoUpgrade(manifest, quiet=False):
+  wrapper = WrapperModule()
+  if wrapper.NeedSetupGnuPG():
+    wrapper.SetupGnuPG(quiet)
   for project in manifest.projects.values():
     if project.Exists:
       project.PostRepoUpgrade()
@@ -711,7 +697,7 @@
       try:
         try:
           self._times = pickle.load(f)
-        except:
+        except IOError:
           try:
             os.remove(self._path)
           except OSError:
diff --git a/subcmds/upload.py b/subcmds/upload.py
index 84a5e44..39721ac 100644
--- a/subcmds/upload.py
+++ b/subcmds/upload.py
@@ -297,7 +297,7 @@
     try:
       # refs/changes/XYZ/N --> XYZ
       return refs.get(last_pub).split('/')[-2]
-    except:
+    except (AttributeError, IndexError):
       return ""
 
   def _UploadAndReport(self, opt, todo, original_people):