Collects a list of all ignore patterns configured in a local Git repository
  as specified in the Git documentation. See
  https://git-scm.com/docs/gitignore#_description

  The returned #IgnoreListCollection is guaranteed to contain at least one
  #IgnoreList with #IgnoreList.root pointing to the specified *root_dir* (which
  defaults to the parent directory of *git_dir*) as the first element.

def parse(ignore_file='.gitignore', git_dir='.git', additional_files=(),
          global_=True, root_dir=None, defaults=True):
  """
  Collects a list of all ignore patterns configured in a local Git repository
  as specified in the Git documentation. See
  https://git-scm.com/docs/gitignore#_description

  The returned #IgnoreListCollection is guaranteed to contain at least one
  #IgnoreList with #IgnoreList.root pointing to the specified *root_dir* (which
  defaults to the parent directory of *git_dir*) as the first element.
  """

  result = IgnoreListCollection()

  if root_dir is None:
    if git_dir is None:
      raise ValueError("root_dir or git_dir must be specified")
    root_dir = os.path.dirname(os.path.abspath(git_dir))

  def parse(filename, root=None):
    if os.path.isfile(filename):
      if root is None:
        root = os.path.dirname(os.path.abspath(filename))
      with open(filename) as fp:
        result.parse(fp, root)

  result.append(IgnoreList(root_dir))
  if ignore_file is not None:
    parse(ignore_file)
  for filename in additional_files:
    parse(filename)
  if git_dir is not None:
    parse(os.path.join(git_dir, 'info', 'exclude'), root_dir)
  if global_:
    # TODO: Read the core.excludeFiles configuration value.
    parse(os.path.expanduser('~/.gitignore'), root_dir)
  if defaults:
    result.append(get_defaults(root_dir))
  return result