Merge tag 'v2.33'

Resolved merge conflicts in error.py, project.py, and subcmds/sync.py.
Conflicts were caused by upstream changes to style.

* tag 'v2.33':
  sync: Fix how sync times for shared projects are recorded
  manifest: add support for revision in include
  sync: Display total elapsed fetch time
  [SyncAnalysisState] Preserve synctime µs
  tests: do not allow underscores in cli options
  upload: Add `--no-follow-tags` by default to git push
  run_tests: Check flake8
  Update abandon to support multiple branches
  run_tests: Always check black and check it last
  Format codebase with black and check formatting in CQ
  Make black with line length 80 repo's code style
  docs: update Focal Python version
diff --git a/error.py b/error.py
index 80e6004..c8d092e 100644
--- a/error.py
+++ b/error.py
@@ -14,126 +14,116 @@
 
 
 class ManifestParseError(Exception):
-  """Failed to parse the manifest file.
-  """
+    """Failed to parse the manifest file."""
 
 
 class ManifestInvalidRevisionError(ManifestParseError):
-  """The revision value in a project is incorrect.
-  """
+    """The revision value in a project is incorrect."""
 
 
 class ManifestInvalidPathError(ManifestParseError):
-  """A path used in <copyfile> or <linkfile> is incorrect.
-  """
+    """A path used in <copyfile> or <linkfile> is incorrect."""
 
 
 class NoManifestException(Exception):
-  """The required manifest does not exist.
-  """
+    """The required manifest does not exist."""
 
-  def __init__(self, path, reason):
-    super().__init__(path, reason)
-    self.path = path
-    self.reason = reason
+    def __init__(self, path, reason):
+        super().__init__(path, reason)
+        self.path = path
+        self.reason = reason
 
-  def __str__(self):
-    return self.reason
+    def __str__(self):
+        return self.reason
 
 
 class EditorError(Exception):
-  """Unspecified error from the user's text editor.
-  """
+    """Unspecified error from the user's text editor."""
 
-  def __init__(self, reason):
-    super().__init__(reason)
-    self.reason = reason
+    def __init__(self, reason):
+        super().__init__(reason)
+        self.reason = reason
 
-  def __str__(self):
-    return self.reason
+    def __str__(self):
+        return self.reason
 
 
 class GitError(Exception):
-  """Unspecified internal error from git.
-  """
+    """Unspecified internal error from git."""
 
-  def __init__(self, command):
-    super().__init__(command)
-    self.command = command
+    def __init__(self, command):
+        super().__init__(command)
+        self.command = command
 
-  def __str__(self):
-    return self.command
+    def __str__(self):
+        return self.command
 
 
 class UploadError(Exception):
-  """A bundle upload to Gerrit did not succeed.
-  """
+    """A bundle upload to Gerrit did not succeed."""
 
-  def __init__(self, reason):
-    super().__init__(reason)
-    self.reason = reason
+    def __init__(self, reason):
+        super().__init__(reason)
+        self.reason = reason
 
-  def __str__(self):
-    return self.reason
+    def __str__(self):
+        return self.reason
 
 
 class DownloadError(Exception):
-  """Cannot download a repository.
-  """
+    """Cannot download a repository."""
 
-  def __init__(self, reason):
-    super().__init__(reason)
-    self.reason = reason
+    def __init__(self, reason):
+        super().__init__(reason)
+        self.reason = reason
 
-  def __str__(self):
-    return self.reason
+    def __str__(self):
+        return self.reason
 
 
 class NoSuchProjectError(Exception):
-  """A specified project does not exist in the work tree.
-  """
+    """A specified project does not exist in the work tree."""
 
-  def __init__(self, name=None):
-    super().__init__(name)
-    self.name = name
+    def __init__(self, name=None):
+        super().__init__(name)
+        self.name = name
 
-  def __str__(self):
-    if self.name is None:
-      return 'in current directory'
-    return self.name
+    def __str__(self):
+        if self.name is None:
+            return "in current directory"
+        return self.name
 
 
 class InvalidProjectGroupsError(Exception):
-  """A specified project is not suitable for the specified groups
-  """
+    """A specified project is not suitable for the specified groups"""
 
-  def __init__(self, name=None):
-    super().__init__(name)
-    self.name = name
+    def __init__(self, name=None):
+        super().__init__(name)
+        self.name = name
 
-  def __str__(self):
-    if self.name is None:
-      return 'in current directory'
-    return self.name
+    def __str__(self):
+        if self.name is None:
+            return "in current directory"
+        return self.name
 
 
 class RepoChangedException(Exception):
-  """Thrown if 'repo sync' results in repo updating its internal
-     repo or manifest repositories.  In this special case we must
-     use exec to re-execute repo with the new code and manifest.
-  """
+    """Thrown if 'repo sync' results in repo updating its internal
+    repo or manifest repositories.  In this special case we must
+    use exec to re-execute repo with the new code and manifest.
+    """
 
-  def __init__(self, extra_args=None):
-    super().__init__(extra_args)
-    self.extra_args = extra_args or []
+    def __init__(self, extra_args=None):
+        super().__init__(extra_args)
+        self.extra_args = extra_args or []
 
 
 class HookError(Exception):
-  """Thrown if a 'repo-hook' could not be run.
+    """Thrown if a 'repo-hook' could not be run.
 
-  The common case is that the file wasn't present when we tried to run it.
-  """
+    The common case is that the file wasn't present when we tried to run it.
+    """
+
 
 class CacheApplyError(Exception):
-  """Thrown when errors happen in 'repo sync' with '--cache-dir' option.
-  """
+    """Thrown when errors happen in 'repo sync' with '--cache-dir' option."""