Beispiel #1
0
def initialize_repo(worktree, gitdir=None):
    """Initialize a git repository for the given `worktree`.

  NB: The given `worktree` must contain at least one file which will be committed to form an initial
  commit.

  :param string worktree: The path to the git work tree.
  :param string gitdir: An optional path to the `.git` dir to use.
  :returns: A `Git` repository object that can be used to interact with the repo.
  :rtype: :class:`pants.scm.git.Git`
  """
    @contextmanager
    def use_gitdir():
        if gitdir:
            yield gitdir
        else:
            with temporary_dir() as d:
                yield d

    with use_gitdir() as git_dir, environment_as(GIT_DIR=git_dir,
                                                 GIT_WORK_TREE=worktree):
        subprocess.check_call(['git', 'init'])
        subprocess.check_call(
            ['git', 'config', 'user.email', '*****@*****.**'])
        # TODO: This method inherits the global git settings, so if a developer has gpg signing on, this
        # will turn that off. We should probably just disable reading from the global config somehow:
        # https://git-scm.com/docs/git-config.
        subprocess.check_call(['git', 'config', 'commit.gpgSign', 'false'])
        subprocess.check_call(['git', 'config', 'user.name', 'Your Name'])
        subprocess.check_call(['git', 'add', '.'])
        subprocess.check_call(['git', 'commit', '-am', 'Add project files.'])

        yield Git(gitdir=git_dir, worktree=worktree)
Beispiel #2
0
def initialize_repo(worktree: str,
                    *,
                    gitdir: Optional[str] = None) -> Iterator[Git]:
    """Initialize a git repository for the given `worktree`.

    NB: The given `worktree` must contain at least one file which will be committed to form an initial
    commit.

    :param worktree: The path to the git work tree.
    :param gitdir: An optional path to the `.git` dir to use.
    :returns: A `Git` repository object that can be used to interact with the repo.
    """
    @contextmanager
    def use_gitdir() -> Iterator[str]:
        if gitdir:
            yield gitdir
        else:
            with temporary_dir() as d:
                yield d

    with use_gitdir() as git_dir, environment_as(GIT_DIR=git_dir,
                                                 GIT_WORK_TREE=worktree):
        subprocess.run(["git", "init"], check=True)
        subprocess.run(["git", "config", "user.email", "*****@*****.**"],
                       check=True)
        # TODO: This method inherits the global git settings, so if a developer has gpg signing on, this
        # will turn that off. We should probably just disable reading from the global config somehow:
        # https://git-scm.com/docs/git-config.
        subprocess.run(["git", "config", "commit.gpgSign", "false"],
                       check=True)
        subprocess.run(["git", "config", "user.name", "Your Name"], check=True)
        subprocess.run(["git", "add", "."], check=True)
        subprocess.run(["git", "commit", "-am", "Add project files."],
                       check=True)
        yield Git(gitdir=git_dir, worktree=worktree)
Beispiel #3
0
  def setUpClass(cls):
    cls.origin = safe_mkdtemp()
    with pushd(cls.origin):
      subprocess.check_call(['git', 'init', '--bare'])

    cls.gitdir = safe_mkdtemp()
    cls.worktree = safe_mkdtemp()

    cls.readme_file = os.path.join(cls.worktree, 'README')

    with environment_as(GIT_DIR=cls.gitdir, GIT_WORK_TREE=cls.worktree):
      cls.init_repo('depot', cls.origin)

      touch(cls.readme_file)
      subprocess.check_call(['git', 'add', 'README'])
      subprocess.check_call(['git', 'commit', '-am', 'initial commit with decode -> \x81b'])
      subprocess.check_call(['git', 'tag', 'first'])
      subprocess.check_call(['git', 'push', '--tags', 'depot', 'master'])
      subprocess.check_call(['git', 'branch', '--set-upstream', 'master', 'depot/master'])

      with safe_open(cls.readme_file, 'w') as readme:
        readme.write('Hello World.')
      subprocess.check_call(['git', 'commit', '-am', 'Update README.'])

    cls.clone2 = safe_mkdtemp()
    with pushd(cls.clone2):
      cls.init_repo('origin', cls.origin)
      subprocess.check_call(['git', 'pull', '--tags', 'origin', 'master:master'])

      with safe_open(os.path.realpath('README'), 'a') as readme:
        readme.write('--')
      subprocess.check_call(['git', 'commit', '-am', 'Update README 2.'])
      subprocess.check_call(['git', 'push', '--tags', 'origin', 'master'])

    cls.git = Git(gitdir=cls.gitdir, worktree=cls.worktree)
Beispiel #4
0
def initialize_repo(worktree, gitdir=None):
  """Initialize a git repository for the given `worktree`.

  NB: The given `worktree` must contain at least one file which will be committed to form an initial
  commit.

  :param string worktree: The path to the git work tree.
  :param string gitdir: An optional path to the `.git` dir to use.
  :returns: A `Git` repository object that can be used to interact with the repo.
  :rtype: :class:`pants.scm.git.Git`
  """
  @contextmanager
  def use_gitdir():
    if gitdir:
      yield gitdir
    else:
      with temporary_dir() as d:
        yield d

  with use_gitdir() as git_dir, environment_as(GIT_DIR=git_dir, GIT_WORK_TREE=worktree):
    subprocess.check_call(['git', 'init'])
    subprocess.check_call(['git', 'config', 'user.email', '*****@*****.**'])
    subprocess.check_call(['git', 'config', 'user.name', 'Your Name'])
    subprocess.check_call(['git', 'add', '.'])
    subprocess.check_call(['git', 'commit', '-am', 'Add project files.'])

    yield Git(gitdir=git_dir, worktree=worktree)
Beispiel #5
0
  def setUp(self):
    self.origin = safe_mkdtemp()
    with pushd(self.origin):
      subprocess.check_call(['git', 'init', '--bare'])

    self.gitdir = safe_mkdtemp()
    self.worktree = safe_mkdtemp()

    self.readme_file = os.path.join(self.worktree, 'README')

    with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree):
      self.init_repo('depot', self.origin)

      touch(self.readme_file)
      subprocess.check_call(['git', 'add', 'README'])
      safe_mkdir(os.path.join(self.worktree, 'dir'))
      with open(os.path.join(self.worktree, 'dir', 'f'), 'w') as f:
        f.write("file in subdir")

      # Make some symlinks
      os.symlink('f', os.path.join(self.worktree, 'dir', 'relative-symlink'))
      os.symlink('no-such-file', os.path.join(self.worktree, 'dir', 'relative-nonexistent'))
      os.symlink('dir/f', os.path.join(self.worktree, 'dir', 'not-absolute\u2764'))
      os.symlink('../README', os.path.join(self.worktree, 'dir', 'relative-dotdot'))
      os.symlink('dir', os.path.join(self.worktree, 'link-to-dir'))
      os.symlink('README/f', os.path.join(self.worktree, 'not-a-dir'))
      os.symlink('loop1', os.path.join(self.worktree, 'loop2'))
      os.symlink('loop2', os.path.join(self.worktree, 'loop1'))

      subprocess.check_call(['git', 'add', 'README', 'dir', 'loop1', 'loop2',
                             'link-to-dir', 'not-a-dir'])
      subprocess.check_call(['git', 'commit', '-am', 'initial commit with decode -> \x81b'])
      self.initial_rev = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip()
      subprocess.check_call(['git', 'tag', 'first'])
      subprocess.check_call(['git', 'push', '--tags', 'depot', 'master'])
      subprocess.check_call(['git', 'branch', '--set-upstream-to', 'depot/master'])

      with safe_open(self.readme_file, 'w') as readme:
        readme.write('Hello World.\u2764'.encode('utf-8'))
      subprocess.check_call(['git', 'commit', '-am', 'Update README.'])

      self.current_rev = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip()

    self.clone2 = safe_mkdtemp()
    with pushd(self.clone2):
      self.init_repo('origin', self.origin)
      subprocess.check_call(['git', 'pull', '--tags', 'origin', 'master:master'])

      with safe_open(os.path.realpath('README'), 'a') as readme:
        readme.write('--')
      subprocess.check_call(['git', 'commit', '-am', 'Update README 2.'])
      subprocess.check_call(['git', 'push', '--tags', 'origin', 'master'])

    self.git = Git(gitdir=self.gitdir, worktree=self.worktree)
 def __call__(self, manifest_entries=None):
     """Returns a dict suitable for passing to 'manifest_entries' in a 'jvm_binary() definition"""
     manifest_entries = manifest_entries or {}
     buildroot = get_buildroot()
     worktree = Git.detect_worktree(
         subdir=os.path.join(buildroot, self._parse_context.rel_path))
     if worktree:
         git = Git(worktree=worktree)
         manifest_entries['Implementation-Version'] = git.commit_id
     manifest_entries['Built-By'] = pwd.getpwuid(os.getuid()).pw_name
     return manifest_entries
Beispiel #7
0
  def test(self):
    self.assertEqual(set(), self.git.changed_files())
    self.assertEqual(set(['README']), self.git.changed_files(from_commit='HEAD^'))

    tip_sha = self.git.commit_id
    self.assertTrue(tip_sha)

    self.assertTrue(tip_sha in self.git.changelog())

    self.assertTrue(self.git.tag_name.startswith('first-'), msg='un-annotated tags should be found')
    self.assertEqual('master', self.git.branch_name)

    def edit_readme():
      with open(self.readme_file, 'a') as readme:
        readme.write('More data.')

    edit_readme()
    with open(os.path.join(self.worktree, 'INSTALL'), 'w') as untracked:
      untracked.write('make install')
    self.assertEqual(set(['README']), self.git.changed_files())
    self.assertEqual(set(['README', 'INSTALL']), self.git.changed_files(include_untracked=True))

    try:
      # These changes should be rejected because our branch point from origin is 1 commit behind
      # the changes pushed there in clone 2.
      self.git.commit('API Changes.')
    except Scm.RemoteException:
      with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree):
        subprocess.check_call(['git', 'reset', '--hard', 'depot/master'])
      self.git.refresh()
      edit_readme()

    self.git.commit('''API '"' " Changes.''')
    self.git.tag('second', message='''Tagged ' " Changes''')

    with temporary_dir() as clone:
      with pushd(clone):
        self.init_repo('origin', self.origin)
        subprocess.check_call(['git', 'pull', '--tags', 'origin', 'master:master'])

        with open(os.path.realpath('README')) as readme:
          self.assertEqual('--More data.', readme.read())

        git = Git()

        # Check that we can pick up committed and uncommitted changes.
        with safe_open(os.path.realpath('CHANGES'), 'w') as changes:
          changes.write('none')
        subprocess.check_call(['git', 'add', 'CHANGES'])
        self.assertEqual(set(['README', 'CHANGES']), git.changed_files(from_commit='first'))

        self.assertEqual('master', git.branch_name)
        self.assertEqual('second', git.tag_name, msg='annotated tags should be found')
    def test_build_file_rev(self):
        # Test that the build_file_rev global option works.  Because the
        # test framework does not yet support bootstrap options, this test
        # in fact just directly calls ScmBuildFile.set_rev.

        with pushd(self.root_dir):
            subprocess.check_call(['git', 'init'])
            subprocess.check_call(
                ['git', 'config', 'user.email', '*****@*****.**'])
            subprocess.check_call(['git', 'config', 'user.name', 'Your Name'])
            subprocess.check_call(['git', 'add', '.'])
            subprocess.check_call(['git', 'commit', '-m' 'initial commit'])

            subprocess.check_call([
                'rm', '-rf', 'path-that-does-exist', 'grandparent', 'BUILD',
                'BUILD.twitter'
            ])

            self._project_tree = ScmProjectTree(self.root_dir,
                                                Git(worktree=self.root_dir),
                                                'HEAD')

            my_buildfile = self.create_buildfile('grandparent/parent/BUILD')
            buildfile = self.create_buildfile(
                'grandparent/parent/BUILD.twitter')

            self.assertEquals(
                OrderedSet([my_buildfile, buildfile]),
                OrderedSet(self.get_build_files_family('grandparent/parent')))

            self.assertEquals(
                OrderedSet([
                    self.create_buildfile(
                        'grandparent/parent/child2/child3/BUILD')
                ]),
                OrderedSet(
                    self.get_build_files_family(
                        'grandparent/parent/child2/child3')))

            buildfiles = self.scan_buildfiles('grandparent')

            self.assertEquals(
                OrderedSet([
                    self.create_buildfile('grandparent/parent/BUILD'),
                    self.create_buildfile('grandparent/parent/BUILD.twitter'),
                    self.create_buildfile('grandparent/parent/child1/BUILD'),
                    self.create_buildfile(
                        'grandparent/parent/child1/BUILD.twitter'),
                    self.create_buildfile(
                        'grandparent/parent/child2/child3/BUILD'),
                    self.create_buildfile('grandparent/parent/child5/BUILD'),
                ]), buildfiles)
Beispiel #9
0
def initialize_repo(worktree):
    """Initialize git repository for the given worktree."""
    gitdir = safe_mkdtemp()
    with environment_as(GIT_DIR=gitdir, GIT_WORK_TREE=worktree):
        subprocess.check_call(['git', 'init'])
        subprocess.check_call(
            ['git', 'config', 'user.email', '*****@*****.**'])
        subprocess.check_call(['git', 'config', 'user.name', 'Your Name'])
        subprocess.check_call(['git', 'add', '.'])
        subprocess.check_call(['git', 'commit', '-am', 'Add project files.'])

        yield Git(gitdir=gitdir, worktree=worktree)

        safe_rmtree(gitdir)
Beispiel #10
0
def get_scm():
  """Returns the pants Scm if any."""
  # TODO(John Sirois): Extract a module/class to carry the bootstrap logic.
  global _SCM
  if not _SCM:
    # We know about git, so attempt an auto-configure
    git_dir = os.path.join(get_buildroot(), '.git')
    if os.path.isdir(git_dir):
      from pants.scm.git import Git
      git = Git(worktree=get_buildroot())
      try:
        log.info('Detected git repository on branch %s' % git.branch_name)
        set_scm(git)
      except git.LocalException:
        pass
  return _SCM
Beispiel #11
0
def get_scm():
    """Returns the pants Scm if any."""
    # TODO(John Sirois): Extract a module/class to carry the bootstrap logic.
    global _SCM
    if not _SCM:
        from pants.scm.git import Git
        # We know about git, so attempt an auto-configure
        worktree = Git.detect_worktree()
        if worktree and os.path.isdir(worktree):
            git = Git(worktree=worktree)
            try:
                log.info('Detected git repository at %s on branch %s' %
                         (worktree, git.branch_name))
                set_scm(git)
            except git.LocalException as e:
                log.info('Failed to load git repository at %s: %s' %
                         (worktree, e))
    return _SCM
Beispiel #12
0
def get_scm() -> Optional[Scm]:
  """Returns the pants Scm if any.

  :API: public
  """
  # TODO(John Sirois): Extract a module/class to carry the bootstrap logic.
  global _SCM
  if _SCM:
    return _SCM
  from pants.scm.git import Git
  # We know about git, so attempt an auto-configure
  worktree = Git.detect_worktree()
  if worktree and os.path.isdir(worktree):
    git = Git(worktree=worktree)
    try:
      logger.debug(f'Detected git repository at {worktree} on branch {git.branch_name}')
      set_scm(git)
    except git.LocalException as e:
      logger.info(f'Failed to load git repository at {worktree}: {e!r}')
  return _SCM
Beispiel #13
0
 def setUp(self):
     super(ScmBuildFileTest, self).setUp()
     ScmBuildFile.set_rev('HEAD')
     ScmBuildFile.set_scm(Git(worktree=self.root_dir))
Beispiel #14
0
    def test_integration(self):
        self.assertEqual(set(), self.git.changed_files())
        self.assertEqual({'README'},
                         self.git.changed_files(from_commit='HEAD^'))

        tip_sha = self.git.commit_id
        self.assertTrue(tip_sha)

        self.assertTrue(tip_sha in self.git.changelog())

        merge_base = self.git.merge_base()
        self.assertTrue(merge_base)

        self.assertTrue(merge_base in self.git.changelog())

        with self.assertRaises(Scm.LocalException):
            self.git.server_url

        with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree):
            with self.mkremote('origin') as origin_uri:
                # We shouldn't be fooled by remotes with origin in their name.
                with self.mkremote('temp_origin'):
                    origin_url = self.git.server_url
                    self.assertEqual(origin_url, origin_uri)

        self.assertTrue(self.git.tag_name.startswith('first-'),
                        msg='un-annotated tags should be found')
        self.assertEqual('master', self.git.branch_name)

        def edit_readme():
            with open(self.readme_file, 'a') as fp:
                fp.write('More data.')

        edit_readme()
        with open(os.path.join(self.worktree, 'INSTALL'), 'w') as untracked:
            untracked.write('make install')
        self.assertEqual({'README'}, self.git.changed_files())
        self.assertEqual({'README', 'INSTALL'},
                         self.git.changed_files(include_untracked=True))

        # Confirm that files outside of a given relative_to path are ignored
        self.assertEqual(set(),
                         self.git.changed_files(relative_to='non-existent'))

        self.git.commit('API Changes.')
        try:
            # These changes should be rejected because our branch point from origin is 1 commit behind
            # the changes pushed there in clone 2.
            self.git.push()
        except Scm.RemoteException:
            with environment_as(GIT_DIR=self.gitdir,
                                GIT_WORK_TREE=self.worktree):
                subprocess.check_call(
                    ['git', 'reset', '--hard', 'depot/master'])
            self.git.refresh()
            edit_readme()

        self.git.commit('''API '"' " Changes.''')
        self.git.push()
        # HEAD is merged into master
        self.assertEqual(self.git.commit_date(self.git.merge_base()),
                         self.git.commit_date('HEAD'))
        self.assertEqual(self.git.commit_date('HEAD'),
                         self.git.commit_date('HEAD'))
        self.git.tag('second', message='''Tagged ' " Changes''')

        with temporary_dir() as clone:
            with pushd(clone):
                self.init_repo('origin', self.origin)
                subprocess.check_call(
                    ['git', 'pull', '--tags', 'origin', 'master:master'])

                with open(os.path.realpath('README'), 'r') as readme:
                    self.assertEqual('--More data.', readme.read())

                git = Git()

                # Check that we can pick up committed and uncommitted changes.
                with safe_open(os.path.realpath('CHANGES'), 'w') as changes:
                    changes.write('none')
                subprocess.check_call(['git', 'add', 'CHANGES'])
                self.assertEqual({'README', 'CHANGES'},
                                 git.changed_files(from_commit='first'))

                self.assertEqual('master', git.branch_name)
                self.assertEqual('second',
                                 git.tag_name,
                                 msg='annotated tags should be found')
Beispiel #15
0
 def mk_project_tree(self, build_root_src):
     return ScmProjectTree(build_root_src, Git(worktree=build_root_src),
                           'HEAD')
Beispiel #16
0
    def test_integration(self):
        self.assertEqual(set(), self.git.changed_files())
        self.assertEqual({"README"},
                         self.git.changed_files(from_commit="HEAD^"))

        tip_sha = self.git.commit_id
        self.assertTrue(tip_sha)

        self.assertTrue(tip_sha in self.git.changelog())

        merge_base = self.git.merge_base()
        self.assertTrue(merge_base)

        self.assertTrue(merge_base in self.git.changelog())

        with self.assertRaises(Scm.LocalException):
            self.git.server_url

        with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree):
            with self.mkremote("origin") as origin_uri:
                # We shouldn't be fooled by remotes with origin in their name.
                with self.mkremote("temp_origin"):
                    origin_url = self.git.server_url
                    self.assertEqual(origin_url, origin_uri)

        self.assertTrue(self.git.tag_name.startswith("first-"),
                        msg="un-annotated tags should be found")
        self.assertEqual("master", self.git.branch_name)

        def edit_readme():
            with open(self.readme_file, "a") as fp:
                fp.write("More data.")

        edit_readme()
        with open(os.path.join(self.worktree, "INSTALL"), "w") as untracked:
            untracked.write("make install")
        self.assertEqual({"README"}, self.git.changed_files())
        self.assertEqual({"README", "INSTALL"},
                         self.git.changed_files(include_untracked=True))

        # Confirm that files outside of a given relative_to path are ignored
        self.assertEqual(set(),
                         self.git.changed_files(relative_to="non-existent"))

        self.git.commit("API Changes.")
        try:
            # These changes should be rejected because our branch point from origin is 1 commit behind
            # the changes pushed there in clone 2.
            self.git.push()
        except Scm.RemoteException:
            with environment_as(GIT_DIR=self.gitdir,
                                GIT_WORK_TREE=self.worktree):
                subprocess.check_call(
                    ["git", "reset", "--hard", "depot/master"])
            self.git.refresh()
            edit_readme()

        self.git.commit("""API '"' " Changes.""")
        self.git.push()
        # HEAD is merged into master
        self.assertEqual(self.git.commit_date(self.git.merge_base()),
                         self.git.commit_date("HEAD"))
        self.assertEqual(self.git.commit_date("HEAD"),
                         self.git.commit_date("HEAD"))
        self.git.tag("second", message="""Tagged ' " Changes""")

        with temporary_dir() as clone:
            with pushd(clone):
                self.init_repo("origin", self.origin)
                subprocess.check_call(
                    ["git", "pull", "--tags", "origin", "master:master"])

                with open(os.path.realpath("README"), "r") as readme:
                    self.assertEqual("--More data.", readme.read())

                git = Git()

                # Check that we can pick up committed and uncommitted changes.
                with safe_open(os.path.realpath("CHANGES"), "w") as changes:
                    changes.write("none")
                subprocess.check_call(["git", "add", "CHANGES"])
                self.assertEqual({"README", "CHANGES"},
                                 git.changed_files(from_commit="first"))

                self.assertEqual("master", git.branch_name)
                self.assertEqual("second",
                                 git.tag_name,
                                 msg="annotated tags should be found")
Beispiel #17
0
    def setUp(self):
        self.origin = safe_mkdtemp()
        with pushd(self.origin):
            subprocess.check_call(["git", "init", "--bare"])

        self.gitdir = safe_mkdtemp()
        self.worktree = safe_mkdtemp()

        self.readme_file = os.path.join(self.worktree, "README")

        with environment_as(GIT_DIR=self.gitdir, GIT_WORK_TREE=self.worktree):
            self.init_repo("depot", self.origin)

            touch(self.readme_file)
            subprocess.check_call(["git", "add", "README"])
            safe_mkdir(os.path.join(self.worktree, "dir"))
            with open(os.path.join(self.worktree, "dir", "f"), "w") as f:
                f.write("file in subdir")

            # Make some symlinks
            os.symlink("f",
                       os.path.join(self.worktree, "dir", "relative-symlink"))
            os.symlink(
                "no-such-file",
                os.path.join(self.worktree, "dir", "relative-nonexistent"))
            os.symlink(
                "dir/f",
                os.path.join(self.worktree, "dir", "not-absolute\u2764"))
            os.symlink("../README",
                       os.path.join(self.worktree, "dir", "relative-dotdot"))
            os.symlink("dir", os.path.join(self.worktree, "link-to-dir"))
            os.symlink("README/f", os.path.join(self.worktree, "not-a-dir"))
            os.symlink("loop1", os.path.join(self.worktree, "loop2"))
            os.symlink("loop2", os.path.join(self.worktree, "loop1"))

            subprocess.check_call([
                "git", "add", "README", "dir", "loop1", "loop2", "link-to-dir",
                "not-a-dir"
            ])
            subprocess.check_call([
                "git", "commit", "-am", "initial commit with decode -> \x81b"
            ])
            self.initial_rev = subprocess.check_output(
                ["git", "rev-parse", "HEAD"]).strip()
            subprocess.check_call(["git", "tag", "first"])
            subprocess.check_call(["git", "push", "--tags", "depot", "master"])
            subprocess.check_call(
                ["git", "branch", "--set-upstream-to", "depot/master"])

            with safe_open(self.readme_file, "wb") as readme:
                readme.write("Hello World.\u2764".encode())
            subprocess.check_call(["git", "commit", "-am", "Update README."])

            self.current_rev = subprocess.check_output(
                ["git", "rev-parse", "HEAD"]).strip()

        self.clone2 = safe_mkdtemp()
        with pushd(self.clone2):
            self.init_repo("origin", self.origin)
            subprocess.check_call(
                ["git", "pull", "--tags", "origin", "master:master"])

            with safe_open(os.path.realpath("README"), "a") as readme:
                readme.write("--")
            subprocess.check_call(["git", "commit", "-am", "Update README 2."])
            subprocess.check_call(
                ["git", "push", "--tags", "origin", "master"])

        self.git = Git(gitdir=self.gitdir, worktree=self.worktree)
 def mk_project_tree(self, build_root, ignore_patterns=None):
     return ScmProjectTree(build_root, Git(worktree=build_root), 'HEAD',
                           ignore_patterns)