def test_working_tree(self):
     temp_dir = tempfile.mkdtemp()
     self.addCleanup(shutil.rmtree, temp_dir)
     worktree_temp_dir = tempfile.mkdtemp()
     self.addCleanup(shutil.rmtree, worktree_temp_dir)
     r = Repo.init(temp_dir)
     self.addCleanup(r.close)
     root_sha = r.do_commit(b'empty commit',
                            committer=b'Test Committer <*****@*****.**>',
                            author=b'Test Author <*****@*****.**>',
                            commit_timestamp=12345,
                            commit_timezone=0,
                            author_timestamp=12345,
                            author_timezone=0)
     r.refs[b'refs/heads/master'] = root_sha
     w = Repo._init_new_working_directory(worktree_temp_dir, r)
     self.addCleanup(w.close)
     new_sha = w.do_commit(b'new commit',
                           committer=b'Test Committer <*****@*****.**>',
                           author=b'Test Author <*****@*****.**>',
                           commit_timestamp=12345,
                           commit_timezone=0,
                           author_timestamp=12345,
                           author_timezone=0)
     w.refs[b'HEAD'] = new_sha
     self.assertEqual(os.path.abspath(r.controldir()),
                      os.path.abspath(w.commondir()))
     self.assertEqual(r.refs.keys(), w.refs.keys())
     self.assertNotEqual(r.head(), w.head())
    def test_get_unstaged_changes(self):
        """Unit test for get_unstaged_changes."""

        repo_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, repo_dir)
        with Repo.init(repo_dir) as repo:

            # Commit a dummy file then modify it
            foo1_fullpath = os.path.join(repo_dir, 'foo1')
            with open(foo1_fullpath, 'wb') as f:
                f.write(b'origstuff')

            foo2_fullpath = os.path.join(repo_dir, 'foo2')
            with open(foo2_fullpath, 'wb') as f:
                f.write(b'origstuff')

            repo.stage(['foo1', 'foo2'])
            repo.do_commit(b'test status',
                           author=b'author <email>',
                           committer=b'committer <email>')

            with open(foo1_fullpath, 'wb') as f:
                f.write(b'newstuff')

            # modify access and modify time of path
            os.utime(foo1_fullpath, (0, 0))

            changes = get_unstaged_changes(repo.open_index(), repo_dir)

            self.assertEqual(list(changes), [b'foo1'])
 def test_create_disk_non_bare_mkdir(self):
     tmp_dir = tempfile.mkdtemp()
     target_dir = os.path.join(tmp_dir, "target")
     self.addCleanup(shutil.rmtree, tmp_dir)
     repo = Repo.init(target_dir, mkdir=True)
     self.assertEqual(os.path.join(target_dir, '.git'), repo._controldir)
     self._check_repo_contents(repo, False)
Пример #4
0
 def test_load_ignore(self):
     tmp_dir = tempfile.mkdtemp()
     self.addCleanup(shutil.rmtree, tmp_dir)
     repo = Repo.init(tmp_dir)
     with open(os.path.join(repo.path, '.gitignore'), 'wb') as f:
         f.write(b'/foo/bar\n')
         f.write(b'/dir2\n')
         f.write(b'/dir3/\n')
     os.mkdir(os.path.join(repo.path, 'dir'))
     with open(os.path.join(repo.path, 'dir', '.gitignore'), 'wb') as f:
         f.write(b'/blie\n')
     with open(os.path.join(repo.path, 'dir', 'blie'), 'wb') as f:
         f.write(b'IGNORED')
     p = os.path.join(repo.controldir(), 'info', 'exclude')
     with open(p, 'wb') as f:
         f.write(b'/excluded\n')
     m = IgnoreFilterManager.from_repo(repo)
     self.assertTrue(m.is_ignored('dir/blie'))
     self.assertIs(None,
                   m.is_ignored(os.path.join('dir', 'bloe')))
     self.assertIs(None, m.is_ignored('dir'))
     self.assertTrue(m.is_ignored(os.path.join('foo', 'bar')))
     self.assertTrue(m.is_ignored(os.path.join('excluded')))
     self.assertTrue(m.is_ignored(os.path.join(
         'dir2', 'fileinignoreddir')))
     self.assertFalse(m.is_ignored('dir3'))
     self.assertTrue(m.is_ignored('dir3/'))
     self.assertTrue(m.is_ignored('dir3/bla'))
 def setUpClass(cls):
     cls.projdir = tempfile.mkdtemp()  # temporary project directory
     cls.repo = Repo.init(cls.projdir)  # test repo
     obj_store = cls.repo.object_store  # test repo object store
     # commit 1 ('2017-01-19T01:06:43')
     cls.c1 = make_commit(
         id=cls.tag_test_data[cls.test_tags[0]][1],
         commit_time=cls.tag_test_data[cls.test_tags[0]][0],
         message=b'unannotated tag',
         author=cls.committer)
     obj_store.add_object(cls.c1)
     # tag 1: unannotated
     cls.t1 = cls.test_tags[0]
     cls.repo[b'refs/tags/' + cls.t1] = cls.c1.id  # add unannotated tag
     # commit 2 ('2017-01-19T01:11:54')
     cls.c2 = make_commit(
         id=cls.tag_test_data[cls.test_tags[1]][1],
         commit_time=cls.tag_test_data[cls.test_tags[1]][0],
         message=b'annotated tag',
         parents=[cls.c1.id],
         author=cls.committer)
     obj_store.add_object(cls.c2)
     # tag 2: annotated ('2017-01-19T01:13:21')
     cls.t2 = make_tag(cls.c2,
                       id=cls.tag_test_data[cls.test_tags[1]][2][1],
                       name=cls.test_tags[1],
                       tag_time=cls.tag_test_data[cls.test_tags[1]][2][0])
     obj_store.add_object(cls.t2)
     cls.repo[b'refs/heads/master'] = cls.c2.id
     cls.repo[b'refs/tags/' + cls.t2.name] = cls.t2.id  # add annotated tag
    def test_symlink(self):
        repo_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, repo_dir)
        with Repo.init(repo_dir) as repo:

            # Populate repo
            filed = Blob.from_string(b'file d')
            filee = Blob.from_string(b'd')

            tree = Tree()
            tree[b'c/d'] = (stat.S_IFREG | 0o644, filed.id)
            tree[b'c/e'] = (stat.S_IFLNK, filee.id)  # symlink

            repo.object_store.add_objects([(o, None)
                                           for o in [filed, filee, tree]])

            build_index_from_tree(repo.path, repo.index_path(),
                                  repo.object_store, tree.id)

            # Verify index entries
            index = repo.open_index()

            # symlink to d
            epath = os.path.join(repo.path, 'c', 'e')
            self.assertTrue(os.path.exists(epath))
            self.assertReasonableIndexEntry(
                index[b'c/e'], stat.S_IFLNK,
                0 if sys.platform == 'win32' else 1, filee.id)
            self.assertFileContents(epath, 'd', symlink=True)
    def test_git_dir(self):
        repo_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, repo_dir)
        with Repo.init(repo_dir) as repo:

            # Populate repo
            filea = Blob.from_string(b'file a')
            filee = Blob.from_string(b'd')

            tree = Tree()
            tree[b'.git/a'] = (stat.S_IFREG | 0o644, filea.id)
            tree[b'c/e'] = (stat.S_IFREG | 0o644, filee.id)

            repo.object_store.add_objects([(o, None)
                                           for o in [filea, filee, tree]])

            build_index_from_tree(repo.path, repo.index_path(),
                                  repo.object_store, tree.id)

            # Verify index entries
            index = repo.open_index()
            self.assertEqual(len(index), 1)

            # filea
            apath = os.path.join(repo.path, '.git', 'a')
            self.assertFalse(os.path.exists(apath))

            # filee
            epath = os.path.join(repo.path, 'c', 'e')
            self.assertTrue(os.path.exists(epath))
            self.assertReasonableIndexEntry(index[b'c/e'],
                                            stat.S_IFREG | 0o644, 1, filee.id)
            self.assertFileContents(epath, b'd')
Пример #8
0
 def setUp(self):
     super(FileSystemBackendTests, self).setUp()
     self.path = tempfile.mkdtemp()
     self.addCleanup(shutil.rmtree, self.path)
     self.repo = Repo.init(self.path)
     if sys.platform == 'win32':
         self.backend = FileSystemBackend(self.path[0] + ':' + os.sep)
     else:
         self.backend = FileSystemBackend()
    def test_nonempty(self):
        repo_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, repo_dir)
        with Repo.init(repo_dir) as repo:

            # Populate repo
            filea = Blob.from_string(b'file a')
            fileb = Blob.from_string(b'file b')
            filed = Blob.from_string(b'file d')

            tree = Tree()
            tree[b'a'] = (stat.S_IFREG | 0o644, filea.id)
            tree[b'b'] = (stat.S_IFREG | 0o644, fileb.id)
            tree[b'c/d'] = (stat.S_IFREG | 0o644, filed.id)

            repo.object_store.add_objects([
                (o, None) for o in [filea, fileb, filed, tree]
            ])

            build_index_from_tree(repo.path, repo.index_path(),
                                  repo.object_store, tree.id)

            # Verify index entries
            index = repo.open_index()
            self.assertEqual(len(index), 3)

            # filea
            apath = os.path.join(repo.path, 'a')
            self.assertTrue(os.path.exists(apath))
            self.assertReasonableIndexEntry(index[b'a'], stat.S_IFREG | 0o644,
                                            6, filea.id)
            self.assertFileContents(apath, b'file a')

            # fileb
            bpath = os.path.join(repo.path, 'b')
            self.assertTrue(os.path.exists(bpath))
            self.assertReasonableIndexEntry(index[b'b'], stat.S_IFREG | 0o644,
                                            6, fileb.id)
            self.assertFileContents(bpath, b'file b')

            # filed
            dpath = os.path.join(repo.path, 'c', 'd')
            self.assertTrue(os.path.exists(dpath))
            self.assertReasonableIndexEntry(index[b'c/d'],
                                            stat.S_IFREG | 0o644, 6, filed.id)
            self.assertFileContents(dpath, b'file d')

            # Verify no extra files
            self.assertEqual(['.git', 'a', 'b', 'c'],
                             sorted(os.listdir(repo.path)))
            self.assertEqual(['d'],
                             sorted(os.listdir(os.path.join(repo.path, 'c'))))
Пример #10
0
 def test_load_ignore_ignorecase(self):
     tmp_dir = tempfile.mkdtemp()
     self.addCleanup(shutil.rmtree, tmp_dir)
     repo = Repo.init(tmp_dir)
     config = repo.get_config()
     config.set(b'core', b'ignorecase', True)
     config.write_to_path()
     with open(os.path.join(repo.path, '.gitignore'), 'wb') as f:
         f.write(b'/foo/bar\n')
         f.write(b'/dir\n')
     m = IgnoreFilterManager.from_repo(repo)
     self.assertTrue(m.is_ignored(os.path.join('dir', 'blie')))
     self.assertTrue(m.is_ignored(os.path.join('DIR', 'blie')))
Пример #11
0
 def test_ignored_contents(self):
     tmp_dir = tempfile.mkdtemp()
     self.addCleanup(shutil.rmtree, tmp_dir)
     repo = Repo.init(tmp_dir)
     with open(os.path.join(repo.path, '.gitignore'), 'wb') as f:
         f.write(b'a/*\n')
         f.write(b'!a/*.txt\n')
     m = IgnoreFilterManager.from_repo(repo)
     os.mkdir(os.path.join(repo.path, 'a'))
     self.assertIs(None, m.is_ignored('a'))
     self.assertIs(None, m.is_ignored('a/'))
     self.assertFalse(m.is_ignored('a/b.txt'))
     self.assertTrue(m.is_ignored('a/c.dat'))
Пример #12
0
def init(path=".", bare=False):
    """Create a new git repository.

    :param path: Path to repository.
    :param bare: Whether to create a bare repository.
    :return: A Repo instance
    """
    if not os.path.exists(path):
        os.mkdir(path)

    if bare:
        return Repo.init_bare(path)
    else:
        return Repo.init(path)
    def test_empty(self):
        repo_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, repo_dir)
        with Repo.init(repo_dir) as repo:
            tree = Tree()
            repo.object_store.add_object(tree)

            build_index_from_tree(repo.path, repo.index_path(),
                                  repo.object_store, tree.id)

            # Verify index entries
            index = repo.open_index()
            self.assertEqual(len(index), 0)

            # Verify no files
            self.assertEqual(['.git'], os.listdir(repo.path))
    def test_shell_hook_commit_msg(self):
        if os.name != 'posix':
            self.skipTest('shell hook tests requires POSIX shell')

        commit_msg_fail = """#!/bin/sh
exit 1
"""

        commit_msg_success = """#!/bin/sh
exit 0
"""

        repo_dir = self.mkdtemp()
        self.addCleanup(shutil.rmtree, repo_dir)
        r = Repo.init(repo_dir)
        self.addCleanup(r.close)

        commit_msg = os.path.join(r.controldir(), 'hooks', 'commit-msg')

        with open(commit_msg, 'w') as f:
            f.write(commit_msg_fail)
        os.chmod(commit_msg, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)

        self.assertRaises(errors.CommitError,
                          r.do_commit,
                          b'failed commit',
                          committer=b'Test Committer <*****@*****.**>',
                          author=b'Test Author <*****@*****.**>',
                          commit_timestamp=12345,
                          commit_timezone=0,
                          author_timestamp=12345,
                          author_timezone=0)

        with open(commit_msg, 'w') as f:
            f.write(commit_msg_success)
        os.chmod(commit_msg, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)

        commit_sha = r.do_commit(
            b'empty commit',
            committer=b'Test Committer <*****@*****.**>',
            author=b'Test Author <*****@*****.**>',
            commit_timestamp=12395,
            commit_timezone=0,
            author_timestamp=12395,
            author_timezone=0)
        self.assertEqual([], r[commit_sha].parents)
Пример #15
0
    def test_add_if_new_symbolic(self):
        # Use an empty repo instead of the default.
        repo_dir = os.path.join(tempfile.mkdtemp(), 'test')
        os.makedirs(repo_dir)
        repo = Repo.init(repo_dir)
        self.addCleanup(tear_down_repo, repo)
        refs = repo.refs

        nines = b'9' * 40
        self.assertEqual(b'ref: refs/heads/master', refs.read_ref(b'HEAD'))
        self.assertFalse(b'refs/heads/master' in refs)
        self.assertTrue(refs.add_if_new(b'HEAD', nines))
        self.assertEqual(b'ref: refs/heads/master', refs.read_ref(b'HEAD'))
        self.assertEqual(nines, refs[b'HEAD'])
        self.assertEqual(nines, refs[b'refs/heads/master'])
        self.assertFalse(refs.add_if_new(b'HEAD', b'1' * 40))
        self.assertEqual(nines, refs[b'HEAD'])
        self.assertEqual(nines, refs[b'refs/heads/master'])
    def setUp(self):
        super(GraftsInRepoTests, self).setUp()
        self._repo_dir = os.path.join(tempfile.mkdtemp())
        r = self._repo = Repo.init(self._repo_dir)
        self.addCleanup(shutil.rmtree, self._repo_dir)

        self._shas = []

        commit_kwargs = {
            'committer': b'Test Committer <*****@*****.**>',
            'author': b'Test Author <*****@*****.**>',
            'commit_timestamp': 12395,
            'commit_timezone': 0,
            'author_timestamp': 12395,
            'author_timezone': 0,
        }

        self._shas.append(r.do_commit(b'empty commit', **commit_kwargs))
        self._shas.append(r.do_commit(b'empty commit', **commit_kwargs))
        self._shas.append(r.do_commit(b'empty commit', **commit_kwargs))
    def test_git_submodule_exists(self):
        repo_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, repo_dir)
        with Repo.init(repo_dir) as repo:
            filea = Blob.from_string(b'file alalala')

            subtree = Tree()
            subtree[b'a'] = (stat.S_IFREG | 0o644, filea.id)

            c = Commit()
            c.tree = subtree.id
            c.committer = c.author = b'Somebody <*****@*****.**>'
            c.commit_time = c.author_time = 42342
            c.commit_timezone = c.author_timezone = 0
            c.parents = []
            c.message = b'Subcommit'

            tree = Tree()
            tree[b'c'] = (S_IFGITLINK, c.id)

            os.mkdir(os.path.join(repo_dir, 'c'))
            repo.object_store.add_objects([(o, None) for o in [tree]])

            build_index_from_tree(repo.path, repo.index_path(),
                                  repo.object_store, tree.id)

            # Verify index entries
            index = repo.open_index()
            self.assertEqual(len(index), 1)

            # filea
            apath = os.path.join(repo.path, 'c/a')
            self.assertFalse(os.path.exists(apath))

            # dir c
            cpath = os.path.join(repo.path, 'c')
            self.assertTrue(os.path.isdir(cpath))
            self.assertEqual(index[b'c'][4], S_IFGITLINK)  # mode
            self.assertEqual(index[b'c'][8], c.id)  # sha
    def test_get_unstaged_deleted_changes(self):
        """Unit test for get_unstaged_changes."""

        repo_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, repo_dir)
        with Repo.init(repo_dir) as repo:

            # Commit a dummy file then remove it
            foo1_fullpath = os.path.join(repo_dir, 'foo1')
            with open(foo1_fullpath, 'wb') as f:
                f.write(b'origstuff')

            repo.stage(['foo1'])
            repo.do_commit(b'test status',
                           author=b'author <email>',
                           committer=b'committer <email>')

            os.unlink(foo1_fullpath)

            changes = get_unstaged_changes(repo.open_index(), repo_dir)

            self.assertEqual(list(changes), [b'foo1'])
    def setUp(self):
        super(BuildRepoRootTests, self).setUp()
        self._repo_dir = self.get_repo_dir()
        os.makedirs(self._repo_dir)
        r = self._repo = Repo.init(self._repo_dir)
        self.addCleanup(tear_down_repo, r)
        self.assertFalse(r.bare)
        self.assertEqual(b'ref: refs/heads/master', r.refs.read_ref(b'HEAD'))
        self.assertRaises(KeyError, lambda: r.refs[b'refs/heads/master'])

        with open(os.path.join(r.path, 'a'), 'wb') as f:
            f.write(b'file contents')
        r.stage(['a'])
        commit_sha = r.do_commit(
            b'msg',
            committer=b'Test Committer <*****@*****.**>',
            author=b'Test Author <*****@*****.**>',
            commit_timestamp=12345,
            commit_timezone=0,
            author_timestamp=12345,
            author_timezone=0)
        self.assertEqual([], r[commit_sha].parents)
        self._root_commit = commit_sha
    def test_norewrite(self):
        repo_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, repo_dir)
        with Repo.init(repo_dir) as repo:
            # Populate repo
            filea = Blob.from_string(b'file a')
            filea_path = os.path.join(repo_dir, 'a')
            tree = Tree()
            tree[b'a'] = (stat.S_IFREG | 0o644, filea.id)

            repo.object_store.add_objects([(o, None) for o in [filea, tree]])

            # First Write
            build_index_from_tree(repo.path, repo.index_path(),
                                  repo.object_store, tree.id)
            # Use sync as metadata can be cached on some FS
            os.sync()
            mtime = os.stat(filea_path).st_mtime

            # Test Rewrite
            build_index_from_tree(repo.path, repo.index_path(),
                                  repo.object_store, tree.id)
            os.sync()
            self.assertEqual(mtime, os.stat(filea_path).st_mtime)

            # Modify content
            with open(filea_path, 'wb') as fh:
                fh.write(b'test a')
            os.sync()
            mtime = os.stat(filea_path).st_mtime

            # Test rewrite
            build_index_from_tree(repo.path, repo.index_path(),
                                  repo.object_store, tree.id)
            os.sync()
            with open(filea_path, 'rb') as fh:
                self.assertEqual(b'file a', fh.read())
    def test_no_decode_encode(self):
        repo_dir = tempfile.mkdtemp()
        repo_dir_bytes = repo_dir.encode(sys.getfilesystemencoding())
        self.addCleanup(shutil.rmtree, repo_dir)
        with Repo.init(repo_dir) as repo:

            # Populate repo
            file = Blob.from_string(b'foo')

            tree = Tree()
            latin1_name = u'À'.encode('latin1')
            latin1_path = os.path.join(repo_dir_bytes, latin1_name)
            utf8_name = u'À'.encode('utf8')
            utf8_path = os.path.join(repo_dir_bytes, utf8_name)
            tree[latin1_name] = (stat.S_IFREG | 0o644, file.id)
            tree[utf8_name] = (stat.S_IFREG | 0o644, file.id)

            repo.object_store.add_objects([(o, None) for o in [file, tree]])

            try:
                os.path.exists(latin1_path)
            except UnicodeDecodeError:
                # This happens e.g. with python3.6 on Windows.
                # It implicitly decodes using utf8, which doesn't work.
                self.skipTest('can not implicitly convert as utf8')

            build_index_from_tree(repo.path, repo.index_path(),
                                  repo.object_store, tree.id)

            # Verify index entries
            index = repo.open_index()
            self.assertIn(latin1_name, index)
            self.assertIn(utf8_name, index)

            self.assertTrue(os.path.exists(latin1_path))

            self.assertTrue(os.path.exists(utf8_path))
Пример #22
0
 def setUp(self):
     super(GitUploadPackTests, self).setUp()
     self.path = tempfile.mkdtemp()
     self.addCleanup(shutil.rmtree, self.path)
     self.repo = Repo.init(self.path)
Пример #23
0
 def setUp(self):
     super(UpdateServerInfoTests, self).setUp()
     self.path = tempfile.mkdtemp()
     self.addCleanup(shutil.rmtree, self.path)
     self.repo = Repo.init(self.path)
Пример #24
0
def clone(source,
          target=None,
          bare=False,
          checkout=None,
          errstream=default_bytes_err_stream,
          outstream=None,
          origin=b"origin",
          **kwargs):
    """Clone a local or remote git repository.

    :param source: Path or URL for source repository
    :param target: Path to target repository (optional)
    :param bare: Whether or not to create a bare repository
    :param checkout: Whether or not to check-out HEAD after cloning
    :param errstream: Optional stream to write progress to
    :param outstream: Optional stream to write progress to (deprecated)
    :param origin: Name of remote from the repository used to clone
    :return: The new repository
    """
    # TODO(jelmer): This code overlaps quite a bit with Repo.clone
    if outstream is not None:
        import warnings
        warnings.warn(
            "outstream= has been deprecated in favour of errstream=.",
            DeprecationWarning,
            stacklevel=3)
        errstream = outstream

    if checkout is None:
        checkout = (not bare)
    if checkout and bare:
        raise ValueError("checkout and bare are incompatible")

    if target is None:
        target = source.split("/")[-1]

    if not os.path.exists(target):
        os.mkdir(target)

    if bare:
        r = Repo.init_bare(target)
    else:
        r = Repo.init(target)

    reflog_message = b'clone: from ' + source.encode('utf-8')
    try:
        fetch_result = fetch(r, source, origin, message=reflog_message)
        target_config = r.get_config()
        if not isinstance(source, bytes):
            source = source.encode(DEFAULT_ENCODING)
        target_config.set((b'remote', origin), b'url', source)
        target_config.set((b'remote', origin), b'fetch',
                          b'+refs/heads/*:refs/remotes/' + origin + b'/*')
        target_config.write_to_path()
        # TODO(jelmer): Support symref capability,
        # https://github.com/jelmer/dulwich/issues/485
        try:
            head = r[fetch_result[b'HEAD']]
        except KeyError:
            head = None
        else:
            r[b'HEAD'] = head.id
        if checkout and not bare and head is not None:
            errstream.write(b'Checking out ' + head.id + b'\n')
            r.reset_index(head.tree)
    except BaseException:
        r.close()
        raise

    return r
    def test_shell_hook_post_commit(self):
        if os.name != 'posix':
            self.skipTest('shell hook tests requires POSIX shell')

        repo_dir = self.mkdtemp()
        self.addCleanup(shutil.rmtree, repo_dir)

        r = Repo.init(repo_dir)
        self.addCleanup(r.close)

        (fd, path) = tempfile.mkstemp(dir=repo_dir)
        os.close(fd)
        post_commit_msg = """#!/bin/sh
rm """ + path + """
"""

        root_sha = r.do_commit(b'empty commit',
                               committer=b'Test Committer <*****@*****.**>',
                               author=b'Test Author <*****@*****.**>',
                               commit_timestamp=12345,
                               commit_timezone=0,
                               author_timestamp=12345,
                               author_timezone=0)
        self.assertEqual([], r[root_sha].parents)

        post_commit = os.path.join(r.controldir(), 'hooks', 'post-commit')

        with open(post_commit, 'wb') as f:
            f.write(post_commit_msg.encode(locale.getpreferredencoding()))
        os.chmod(post_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)

        commit_sha = r.do_commit(
            b'empty commit',
            committer=b'Test Committer <*****@*****.**>',
            author=b'Test Author <*****@*****.**>',
            commit_timestamp=12345,
            commit_timezone=0,
            author_timestamp=12345,
            author_timezone=0)
        self.assertEqual([root_sha], r[commit_sha].parents)

        self.assertFalse(os.path.exists(path))

        post_commit_msg_fail = """#!/bin/sh
exit 1
"""
        with open(post_commit, 'w') as f:
            f.write(post_commit_msg_fail)
        os.chmod(post_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)

        warnings.simplefilter("always", UserWarning)
        self.addCleanup(warnings.resetwarnings)
        warnings_list, restore_warnings = setup_warning_catcher()
        self.addCleanup(restore_warnings)

        commit_sha2 = r.do_commit(
            b'empty commit',
            committer=b'Test Committer <*****@*****.**>',
            author=b'Test Author <*****@*****.**>',
            commit_timestamp=12345,
            commit_timezone=0,
            author_timestamp=12345,
            author_timezone=0)
        expected_warning = UserWarning(
            'post-commit hook failed: Hook post-commit exited with '
            'non-zero status', )
        for w in warnings_list:
            if (type(w) == type(expected_warning)
                    and w.args == expected_warning.args):
                break
        else:
            raise AssertionError('Expected warning %r not in %r' %
                                 (expected_warning, warnings_list))
        self.assertEqual([commit_sha], r[commit_sha2].parents)