code: def git_pieces_from_vcs(
      tag_prefix, root, verbose, runner=run_command
  ):
      """Get version from 'git describe' in the root of the source tree.
  
      This only gets called if the git-archive 'subst' keywords were *not*
      expanded, and _version.py hasn't already been rewritten with a short
      version string, meaning we're inside a checked out source tree.
      """
      GITS = ["git"]
      if sys.platform == "win32":
          GITS = ["git.cmd", "git.exe"]
  
      # GIT_DIR can interfere with correct operation of Versioneer.
      # It may be intended to be passed to the Versioneer-versioned project,
      # but that should not change where we get our version from.
      env = os.environ.copy()
      env.pop("GIT_DIR", None)
      runner = functools.partial(runner, env=env)
  
      _, rc = runner(
          GITS,
          ["rev-parse", "--git-dir"],
          cwd=root,
          hide_stderr=not verbose,
      )
      if rc != 0:
          if verbose:
              print("Directory %s not under git control" % root)
          raise NotThisMethod(
              "'git rev-parse --git-dir' returned error"
          )
  
      # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
      # if there isn't one, this yields HEX[-dirty] (no NUM)
      describe_out, rc = runner(
          GITS,
          [
              "describe",
              "--tags",
              "--dirty",
              "--always",
              "--long",
              "--match",
              f"{tag_prefix}[[:digit:]]*",
          ],
          cwd=root,
      )
      # --long was added in git-1.5.5
      if describe_out is None:
          raise NotThisMethod("'git describe' failed")
      describe_out = describe_out.strip()
      full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root)
      if full_out is None:
          raise NotThisMethod("'git rev-parse' failed")
      full_out = full_out.strip()
  
      pieces = {}
      pieces["long"] = full_out
      pieces["short"] = full_out[:7]  # maybe improved later
      pieces["error"] = None
  
      branch_name, rc = runner(
          GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root
      )
      # --abbrev-ref was added in git-1.6.3
      if rc != 0 or branch_name is None:
          raise NotThisMethod(
              "'git rev-parse --abbrev-ref' returned error"
          )
      branch_name = branch_name.strip()
  
      if branch_name == "HEAD":
          # If we aren't exactly on a branch, pick a branch which represents
          # the current commit. If all else fails, we are on a branchless
          # commit.
          branches, rc = runner(
              GITS, ["branch", "--contains"], cwd=root
          )
          # --contains was added in git-1.5.4
          if rc != 0 or branches is None:
              raise NotThisMethod(
                  "'git branch --contains' returned error"
              )
          branches = branches.split("\n")
  
          # Remove the first line if we're running detached
          if "(" in branches[0]:
              branches.pop(0)
  
          # Strip off the leading "* " from the list of branches.
          branches = [branch[2:] for branch in branches]
          if "master" in branches:
              branch_name = "master"
          elif not branches:
              branch_name = None
          else:
              # Pick the first branch that is returned. Good or bad.
              branch_name = branches[0]
  
      pieces["branch"] = branch_name
  
      # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
      # TAG might have hyphens.
      git_describe = describe_out
  
      # look for -dirty suffix
      dirty = git_describe.endswith("-dirty")
      pieces["dirty"] = dirty
      if dirty:
          git_describe = git_describe[: git_describe.rindex("-dirty")]
  
      # now we have TAG-NUM-gHEX or HEX
  
      if "-" in git_describe:
          # TAG-NUM-gHEX
          mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe)
          if not mo:
              # unparsable. Maybe git-describe is misbehaving?
              pieces["error"] = (
                  "unable to parse git-describe output: '%s'"
                  % describe_out
              )
              return pieces
  
          # tag
          full_tag = mo.group(1)
          if not full_tag.startswith(tag_prefix):
              if verbose:
                  fmt = "tag '%s' doesn't start with prefix '%s'"
                  print(fmt % (full_tag, tag_prefix))
              pieces[
                  "error"
              ] = "tag '%s' doesn't start with prefix '%s'" % (
                  full_tag,
                  tag_prefix,
              )
              return pieces
          pieces["closest-tag"] = full_tag[len(tag_prefix) :]
  
          # distance: number of commits since tag
          pieces["distance"] = int(mo.group(2))
  
          # commit: short hex revision ID
          pieces["short"] = mo.group(3)
  
      else:
          # HEX: no tags
          pieces["closest-tag"] = None
          out, rc = runner(
              GITS, ["rev-list", "HEAD", "--left-right"], cwd=root
          )
          pieces["distance"] = len(
              out.split()
          )  # total number of commits
  
      # commit date: see ISO-8601 comment in git_versions_from_keywords()
      date = runner(
          GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root
      )[0].strip()
      # Use only the last line.  Previous lines may contain GPG signature
      # information.
      date = date.splitlines()[-1]
      pieces["date"] = (
          date.strip().replace(" ", "T", 1).replace(" ", "", 1)
      )
  
      return pieces
  
imports: import errno
  import functools
  import os
  import re
  import subprocess
  import sys
  from typing import Callable, Dict
label_desc: Use image node_id 8 for calling a global function with example usage: git_pieces_from_vcs(tag_prefix, root, verbose, runner) and returns: pieces, pieces, pieces