diff options
Diffstat (limited to 'git/test')
| -rw-r--r-- | git/test/fixtures/uncommon_branch_prefix_FETCH_HEAD | 6 | ||||
| -rw-r--r-- | git/test/fixtures/uncommon_branch_prefix_stderr | 6 | ||||
| -rw-r--r-- | git/test/lib/helper.py | 4 | ||||
| -rw-r--r-- | git/test/test_docs.py | 297 | ||||
| -rw-r--r-- | git/test/test_remote.py | 16 | ||||
| -rw-r--r-- | git/test/test_submodule.py | 24 | 
6 files changed, 340 insertions, 13 deletions
| diff --git a/git/test/fixtures/uncommon_branch_prefix_FETCH_HEAD b/git/test/fixtures/uncommon_branch_prefix_FETCH_HEAD new file mode 100644 index 00000000..7df36f24 --- /dev/null +++ b/git/test/fixtures/uncommon_branch_prefix_FETCH_HEAD @@ -0,0 +1,6 @@ +c2e3c20affa3e2b61a05fdc9ee3061dd416d915e		'refs/pull/1/head' of http://github.com/loic-bot/testrepo +fd8695d980e2c6df62b7785f93fd6292d1e283fb		'refs/pull/1/merge' of http://github.com/loic-bot/testrepo +bb46faf089720d1a3f9e4dc3b11ed5ff77d7e764		'refs/pull/2/head' of http://github.com/loic-bot/testrepo +5faa366d58454eceea811e0e34c502bdd7b37e4b		'refs/pull/2/merge' of http://github.com/loic-bot/testrepo +b3ad3c4f1864b50d4d3e09320947a1a3c34c9ea2		'refs/pull/3/head' of http://github.com/loic-bot/testrepo +71fe57e511776042b009ed4bb281b62b0522b434		'refs/pull/3/merge' of http://github.com/loic-bot/testrepo diff --git a/git/test/fixtures/uncommon_branch_prefix_stderr b/git/test/fixtures/uncommon_branch_prefix_stderr new file mode 100644 index 00000000..5a6aca65 --- /dev/null +++ b/git/test/fixtures/uncommon_branch_prefix_stderr @@ -0,0 +1,6 @@ + = [up to date]      refs/pull/1/head -> pull/1/head + = [up to date]      refs/pull/1/merge -> pull/1/merge + = [up to date]      refs/pull/2/head -> pull/2/head + = [up to date]      refs/pull/2/merge -> pull/2/merge + = [up to date]      refs/pull/3/head -> pull/3/head + = [up to date]      refs/pull/3/merge -> pull/3/merge diff --git a/git/test/lib/helper.py b/git/test/lib/helper.py index c5c5a620..8300f272 100644 --- a/git/test/lib/helper.py +++ b/git/test/lib/helper.py @@ -275,6 +275,10 @@ class TestBase(TestCase):        of the project history ( to assure tests don't fail for others ).      """ +    def _small_repo_url(self): +        """:return" a path to a small, clonable repository""" +        return os.path.join(self.rorepo.working_tree_dir, 'git/ext/gitdb/gitdb/ext/smmap') +      @classmethod      def setUpClass(cls):          """ diff --git a/git/test/test_docs.py b/git/test/test_docs.py index 9a04784d..965d10fb 100644 --- a/git/test/test_docs.py +++ b/git/test/test_docs.py @@ -14,6 +14,7 @@ class Tutorials(TestBase):      @with_rw_directory      def test_init_repo_object(self, rw_dir): +        # [1-test_init_repo_object]          from git import Repo          join = os.path.join @@ -36,9 +37,8 @@ class Tutorials(TestBase):          # ![3-test_init_repo_object]          # [4-test_init_repo_object] -        repo.is_dirty() -        # False -        repo.untracked_files +        assert not bare_repo.is_dirty()  # check the dirty state +        repo.untracked_files             # retrieve a list of untracked files          # ['my_untracked_file']          # ![4-test_init_repo_object] @@ -178,6 +178,297 @@ class Tutorials(TestBase):          # ![14-test_init_repo_object]      @with_rw_directory +    def test_references_and_objects(self, rw_dir): +        # [1-test_references_and_objects] +        import git +        repo = git.Repo.clone_from(self._small_repo_url(), os.path.join(rw_dir, 'repo'), branch='master') + +        heads = repo.heads +        master = heads.master       # lists can be accessed by name for convenience +        master.commit               # the commit pointed to by head called master +        master.rename('new_name')   # rename heads +        master.rename('master') +        # ![1-test_references_and_objects] + +        # [2-test_references_and_objects] +        tags = repo.tags +        tagref = tags[0] +        tagref.tag                  # tags may have tag objects carrying additional information +        tagref.commit               # but they always point to commits +        repo.delete_tag(tagref)     # delete or +        repo.create_tag("my_tag")   # create tags using the repo for convenience +        # ![2-test_references_and_objects] + +        # [3-test_references_and_objects] +        head = repo.head            # the head points to the active branch/ref +        master = head.reference     # retrieve the reference the head points to +        master.commit               # from here you use it as any other reference +        # ![3-test_references_and_objects] + +        # [4-test_references_and_objects] +        log = master.log() +        log[0]                      # first (i.e. oldest) reflog entry +        log[-1]                     # last (i.e. most recent) reflog entry +        # ![4-test_references_and_objects] + +        # [5-test_references_and_objects] +        new_branch = repo.create_head('new')     # create a new one +        new_branch.commit = 'HEAD~10'            # set branch to another commit without changing index or working trees +        repo.delete_head(new_branch)             # delete an existing head - only works if it is not checked out +        # ![5-test_references_and_objects] + +        # [6-test_references_and_objects] +        new_tag = repo.create_tag('my_new_tag', message='my message') +        # You cannot change the commit a tag points to. Tags need to be re-created +        self.failUnlessRaises(AttributeError, setattr, new_tag, 'commit', repo.commit('HEAD~1')) +        repo.delete_tag(new_tag) +        # ![6-test_references_and_objects] + +        # [7-test_references_and_objects] +        new_branch = repo.create_head('another-branch') +        repo.head.reference = new_branch +        # ![7-test_references_and_objects] + +        # [8-test_references_and_objects] +        hc = repo.head.commit +        hct = hc.tree +        hc != hct +        hc != repo.tags[0] +        hc == repo.head.reference.commit +        # ![8-test_references_and_objects] + +        # [9-test_references_and_objects] +        assert hct.type == 'tree'           # preset string type, being a class attribute +        assert hct.size > 0                 # size in bytes +        assert len(hct.hexsha) == 40 +        assert len(hct.binsha) == 20 +        # ![9-test_references_and_objects] + +        # [10-test_references_and_objects] +        assert hct.path == ''                  # root tree has no path +        assert hct.trees[0].path != ''         # the first contained item has one though +        assert hct.mode == 0o40000              # trees have the mode of a linux directory +        assert hct.blobs[0].mode == 0o100644   # blobs have a specific mode though comparable to a standard linux fs +        # ![10-test_references_and_objects] + +        # [11-test_references_and_objects] +        hct.blobs[0].data_stream.read()        # stream object to read data from +        hct.blobs[0].stream_data(open(os.path.join(rw_dir, 'blob_data'), 'wb'))  # write data to given stream +        # ![11-test_references_and_objects] + +        # [12-test_references_and_objects] +        repo.commit('master') +        repo.commit('v0.8.1') +        repo.commit('HEAD~10') +        # ![12-test_references_and_objects] + +        # [13-test_references_and_objects] +        fifty_first_commits = list(repo.iter_commits('master', max_count=50)) +        assert len(fifty_first_commits) == 50 +        # this will return commits 21-30 from the commit list as traversed backwards master +        ten_commits_past_twenty = list(repo.iter_commits('master', max_count=10, skip=20)) +        assert len(ten_commits_past_twenty) == 10 +        assert fifty_first_commits[20:30] == ten_commits_past_twenty +        # ![13-test_references_and_objects] + +        # [14-test_references_and_objects] +        headcommit = repo.head.commit +        assert len(headcommit.hexsha) == 40 +        assert len(headcommit.parents) > 0 +        assert headcommit.tree.type == 'tree' +        assert headcommit.author.name == 'Sebastian Thiel' +        assert isinstance(headcommit.authored_date, int) +        assert headcommit.committer.name == 'Sebastian Thiel' +        assert isinstance(headcommit.committed_date, int) +        assert headcommit.message != '' +        # ![14-test_references_and_objects] + +        # [15-test_references_and_objects] +        import time +        time.asctime(time.gmtime(headcommit.committed_date)) +        time.strftime("%a, %d %b %Y %H:%M", time.gmtime(headcommit.committed_date)) +        # ![15-test_references_and_objects] + +        # [16-test_references_and_objects] +        assert headcommit.parents[0].parents[0].parents[0] == repo.commit('master^^^') +        # ![16-test_references_and_objects] + +        # [17-test_references_and_objects] +        tree = repo.heads.master.commit.tree +        assert len(tree.hexsha) == 40 +        # ![17-test_references_and_objects] + +        # [18-test_references_and_objects] +        assert len(tree.trees) > 0          # trees are subdirectories +        assert len(tree.blobs) > 0          # blobs are files +        assert len(tree.blobs) + len(tree.trees) == len(tree) +        # ![18-test_references_and_objects] + +        # [19-test_references_and_objects] +        assert tree['smmap'] == tree / 'smmap'          # access by index and by sub-path +        for entry in tree:                                         # intuitive iteration of tree members +            print(entry) +        blob = tree.trees[0].blobs[0]                              # let's get a blob in a sub-tree +        assert blob.name +        assert len(blob.path) < len(blob.abspath) +        assert tree.trees[0].name + '/' + blob.name == blob.path   # this is how the relative blob path is generated +        assert tree[blob.path] == blob                             # you can use paths like 'dir/file' in tree[...] +        # ![19-test_references_and_objects] + +        # [20-test_references_and_objects] +        assert tree / 'smmap' == tree['smmap'] +        assert tree / blob.path == tree[blob.path] +        # ![20-test_references_and_objects] + +        # [21-test_references_and_objects] +        # This example shows the various types of allowed ref-specs +        assert repo.tree() == repo.head.commit.tree +        past = repo.commit('HEAD~5') +        assert repo.tree(past) == repo.tree(past.hexsha) +        assert repo.tree('v0.8.1').type == 'tree'               # yes, you can provide any refspec - works everywhere +        # ![21-test_references_and_objects] + +        # [22-test_references_and_objects] +        assert len(tree) < len(list(tree.traverse())) +        # ![22-test_references_and_objects] + +        # [23-test_references_and_objects] +        index = repo.index +        # The index contains all blobs in a flat list +        assert len(list(index.iter_blobs())) == len([o for o in repo.head.commit.tree.traverse() if o.type == 'blob']) +        # Access blob objects +        for (path, stage), entry in index.entries.items(): +            pass +        new_file_path = os.path.join(repo.working_tree_dir, 'new-file-name') +        open(new_file_path, 'w').close() +        index.add([new_file_path])                                             # add a new file to the index +        index.remove(['LICENSE'])                                              # remove an existing one +        assert os.path.isfile(os.path.join(repo.working_tree_dir, 'LICENSE'))  # working tree is untouched + +        assert index.commit("my commit message").type == 'commit'              # commit changed index +        repo.active_branch.commit = repo.commit('HEAD~1')                      # forget last commit + +        from git import Actor +        author = Actor("An author", "author@example.com") +        committer = Actor("A committer", "committer@example.com") +        # commit by commit message and author and committer +        index.commit("my commit message", author=author, committer=committer) +        # ![23-test_references_and_objects] + +        # [24-test_references_and_objects] +        from git import IndexFile +        # loads a tree into a temporary index, which exists just in memory +        IndexFile.from_tree(repo, 'HEAD~1') +        # merge two trees three-way into memory +        merge_index = IndexFile.from_tree(repo, 'HEAD~10', 'HEAD', repo.merge_base('HEAD~10', 'HEAD')) +        # and persist it +        merge_index.write(os.path.join(rw_dir, 'merged_index')) +        # ![24-test_references_and_objects] + +        # [25-test_references_and_objects] +        empty_repo = git.Repo.init(os.path.join(rw_dir, 'empty')) +        origin = empty_repo.create_remote('origin', repo.remotes.origin.url) +        assert origin.exists() +        assert origin == empty_repo.remotes.origin == empty_repo.remotes['origin'] +        origin.fetch()                  # assure we actually have data. fetch() returns useful information +        # Setup a local tracking branch of a remote branch +        empty_repo.create_head('master', origin.refs.master).set_tracking_branch(origin.refs.master) +        origin.rename('new_origin')   # rename remotes +        # push and pull behaves similarly to `git push|pull` +        origin.pull() +        origin.push() +        # assert not empty_repo.delete_remote(origin).exists()     # create and delete remotes +        # ![25-test_references_and_objects] + +        # [26-test_references_and_objects] +        assert origin.url == repo.remotes.origin.url +        cw = origin.config_writer +        cw.set("pushurl", "other_url") +        cw.release() + +        # Please note that in python 2, writing origin.config_writer.set(...) is totally safe. +        # In py3 __del__ calls can be delayed, thus not writing changes in time. +        # ![26-test_references_and_objects] + +        # [27-test_references_and_objects] +        hcommit = repo.head.commit +        hcommit.diff()                  # diff tree against index +        hcommit.diff('HEAD~1')          # diff tree against previous tree +        hcommit.diff(None)              # diff tree against working tree +         +        index = repo.index +        index.diff()                    # diff index against itself yielding empty diff +        index.diff(None)                # diff index against working copy +        index.diff('HEAD')              # diff index against current HEAD tree +        # ![27-test_references_and_objects] + +        # [28-test_references_and_objects] +        # Traverse added Diff objects only +        for diff_added in hcommit.diff('HEAD~1').iter_change_type('A'): +            print(diff_added) +        # ![28-test_references_and_objects] + +        # [29-test_references_and_objects] +        # Reset our working tree 10 commits into the past +        past_branch = repo.create_head('past_branch', 'HEAD~10') +        repo.head.reference = past_branch +        assert not repo.head.is_detached +        # reset the index and working tree to match the pointed-to commit +        repo.head.reset(index=True, working_tree=True) + +        # To detach your head, you have to point to a commit directy +        repo.head.reference = repo.commit('HEAD~5') +        assert repo.head.is_detached +        # now our head points 15 commits into the past, whereas the working tree +        # and index are 10 commits in the past +        # ![29-test_references_and_objects] + +        # [30-test_references_and_objects] +        # checkout the branch using git-checkout. It will fail as the working tree appears dirty +        self.failUnlessRaises(git.GitCommandError, repo.heads.master.checkout) +        repo.heads.past_branch.checkout() +        # ![30-test_references_and_objects] + +        # [31-test_references_and_objects] +        git = repo.git +        git.checkout('HEAD', b="my_new_branch")         # create a new branch +        git.branch('another-new-one') +        git.branch('-D', 'another-new-one')             # pass strings for full control over argument order +        git.for_each_ref()                              # '-' becomes '_' when calling it +        # ![31-test_references_and_objects] + +        # [32-test_references_and_objects] +        private_key_file = os.path.join(rw_dir, 'id_rsa_deployment_key') +        with repo.git.sshkey(private_key_file): +            # Note that we don't actually make the call here, as our test-setup doesn't permit it to  +            # succeed. +            # It will in your case :) +            repo.remotes.origin.fetch +        # ![32-test_references_and_objects] + +    def test_submodules(self): +        # [1-test_submodules] +        repo = self.rorepo +        sms = repo.submodules + +        assert len(sms) == 1 +        sm = sms[0] +        assert sm.name == 'gitdb'                         # git-python has gitdb as single submodule ... +        assert sm.children()[0].name == 'smmap'           # ... which has smmap as single submodule +         +        # The module is the repository referenced by the submodule +        assert sm.module_exists()                         # the module is available, which doesn't have to be the case. +        assert sm.module().working_tree_dir.endswith('gitdb') +        # the submodule's absolute path is the module's path +        assert sm.abspath == sm.module().working_tree_dir +        assert len(sm.hexsha) == 40                       # Its sha defines the commit to checkout +        assert sm.exists()                                # yes, this submodule is valid and exists +        # read its configuration conveniently +        assert sm.config_reader().get_value('path') == sm.path +        assert len(sm.children()) == 1                    # query the submodule hierarchy +        # ![1-test_submodules] +         +    @with_rw_directory      def test_add_file_and_commit(self, rw_dir):          import git diff --git a/git/test/test_remote.py b/git/test/test_remote.py index bf2f76a8..98d74d8b 100644 --- a/git/test/test_remote.py +++ b/git/test/test_remote.py @@ -7,7 +7,8 @@  from git.test.lib import (      TestBase,      with_rw_repo, -    with_rw_and_rw_remote_repo +    with_rw_and_rw_remote_repo, +    fixture  )  from git import (      RemoteProgress, @@ -520,3 +521,16 @@ class TestRemote(TestBase):          assert type(fi.ref) is Reference          assert fi.ref.path == "refs/something/branch" + +    def test_uncommon_branch_names(self): +        stderr_lines = fixture('uncommon_branch_prefix_stderr').decode('ascii').splitlines() +        fetch_lines = fixture('uncommon_branch_prefix_FETCH_HEAD').decode('ascii').splitlines() + +        # The contents of the files above must be fetched with a custom refspec: +        # +refs/pull/*:refs/heads/pull/* +        res = [FetchInfo._from_line('ShouldntMatterRepo', stderr, fetch_line) +               for stderr, fetch_line in zip(stderr_lines, fetch_lines)] +        assert len(res) +        assert res[0].remote_ref_path == 'refs/pull/1/head' +        assert res[0].ref.path == 'refs/heads/pull/1/head' +        assert isinstance(res[0].ref, Head) diff --git a/git/test/test_submodule.py b/git/test/test_submodule.py index 1d4cf178..459e2030 100644 --- a/git/test/test_submodule.py +++ b/git/test/test_submodule.py @@ -264,6 +264,15 @@ class TestSubmodule(TestBase):              ########################              # must delete something              self.failUnlessRaises(ValueError, csm.remove, module=False, configuration=False) + +            # module() is supposed to point to gitdb, which has a child-submodule whose URL is still pointing +            # to github. To save time, we will change it to +            csm.set_parent_commit(csm.repo.head.commit) +            cw = csm.config_writer() +            cw.set_value('url', self._small_repo_url()) +            cw.release() +            csm.repo.index.commit("adjusted URL to point to local source, instead of the internet") +              # We have modified the configuration, hence the index is dirty, and the              # deletion will fail              # NOTE: As we did  a few updates in the meanwhile, the indices were reset @@ -651,13 +660,10 @@ class TestSubmodule(TestBase):                                    url=empty_repo_dir, no_checkout=checkout_mode and True or False)          # end for each checkout mode -    def _submodule_url(self): -        return os.path.join(self.rorepo.working_tree_dir, 'git/ext/gitdb/gitdb/ext/smmap') -      @with_rw_directory      def test_git_submodules(self, rwdir):          parent = git.Repo.init(os.path.join(rwdir, 'parent')) -        parent.git.submodule('add', self._submodule_url(), 'module') +        parent.git.submodule('add', self._small_repo_url(), 'module')          parent.index.commit("added submodule")          assert len(parent.submodules) == 1 @@ -665,7 +671,7 @@ class TestSubmodule(TestBase):          assert sm.exists() and sm.module_exists() -        clone = git.Repo.clone_from(self._submodule_url(), +        clone = git.Repo.clone_from(self._small_repo_url(),                                      os.path.join(parent.working_tree_dir, 'existing-subrepository'))          sm2 = parent.create_submodule('nongit-file-submodule', clone.working_tree_dir)          assert len(parent.submodules) == 2 @@ -684,7 +690,7 @@ class TestSubmodule(TestBase):      def test_git_submodule_compatibility(self, rwdir):          parent = git.Repo.init(os.path.join(rwdir, 'parent'))          sm_path = 'submodules/intermediate/one' -        sm = parent.create_submodule('mymodules/myname', sm_path, url=self._submodule_url()) +        sm = parent.create_submodule('mymodules/myname', sm_path, url=self._small_repo_url())          parent.index.commit("added submodule")          def assert_exists(sm, value=True): @@ -714,7 +720,7 @@ class TestSubmodule(TestBase):          # Add additional submodule level          csm = sm.module().create_submodule('nested-submodule', 'nested-submodule/working-tree', -                                           url=self._submodule_url()) +                                           url=self._small_repo_url())          sm.module().index.commit("added nested submodule")          sm_head_commit = sm.module().commit()          assert_exists(csm) @@ -759,7 +765,7 @@ class TestSubmodule(TestBase):      def test_rename(self, rwdir):          parent = git.Repo.init(os.path.join(rwdir, 'parent'))          sm_name = 'mymodules/myname' -        sm = parent.create_submodule(sm_name, sm_name, url=self._submodule_url()) +        sm = parent.create_submodule(sm_name, sm_name, url=self._small_repo_url())          parent.index.commit("Added submodule")          assert sm.rename(sm_name) is sm and sm.name == sm_name @@ -782,7 +788,7 @@ class TestSubmodule(TestBase):      def test_branch_renames(self, rw_dir):          # Setup initial sandbox:          # parent repo has one submodule, which has all the latest changes -        source_url = self._submodule_url() +        source_url = self._small_repo_url()          sm_source_repo = git.Repo.clone_from(source_url, os.path.join(rw_dir, 'sm-source'), b='master')          parent_repo = git.Repo.init(os.path.join(rw_dir, 'parent'))          sm = parent_repo.create_submodule('mysubmodule', 'subdir/submodule', | 
