コード例 #1
0
ファイル: test_index.py プロジェクト: barry-scott/GitPython
    def test_index_file_from_tree(self, rw_repo):
        if sys.version_info < (2, 7):
            ## Skipped, not `assertRaisesRegexp` in py2.6
            return
        common_ancestor_sha = "5117c9c8a4d3af19a9958677e45cda9269de1541"
        cur_sha = "4b43ca7ff72d5f535134241e7c797ddc9c7a3573"
        other_sha = "39f85c4358b7346fee22169da9cad93901ea9eb9"

        # simple index from tree
        base_index = IndexFile.from_tree(rw_repo, common_ancestor_sha)
        assert base_index.entries
        self._cmp_tree_index(common_ancestor_sha, base_index)

        # merge two trees - its like a fast-forward
        two_way_index = IndexFile.from_tree(rw_repo, common_ancestor_sha, cur_sha)
        assert two_way_index.entries
        self._cmp_tree_index(cur_sha, two_way_index)

        # merge three trees - here we have a merge conflict
        three_way_index = IndexFile.from_tree(rw_repo, common_ancestor_sha, cur_sha, other_sha)
        assert len(list(e for e in three_way_index.entries.values() if e.stage != 0))

        # ITERATE BLOBS
        merge_required = lambda t: t[0] != 0
        merge_blobs = list(three_way_index.iter_blobs(merge_required))
        assert merge_blobs
        assert merge_blobs[0][0] in (1, 2, 3)
        assert isinstance(merge_blobs[0][1], Blob)

        # test BlobFilter
        prefix = 'lib/git'
        for stage, blob in base_index.iter_blobs(BlobFilter([prefix])):  # @UnusedVariable
            assert blob.path.startswith(prefix)

        # writing a tree should fail with an unmerged index
        self.failUnlessRaises(UnmergedEntriesError, three_way_index.write_tree)

        # removed unmerged entries
        unmerged_blob_map = three_way_index.unmerged_blobs()
        assert unmerged_blob_map

        # pick the first blob at the first stage we find and use it as resolved version
        three_way_index.resolve_blobs(l[0][1] for l in unmerged_blob_map.values())
        tree = three_way_index.write_tree()
        assert isinstance(tree, Tree)
        num_blobs = 0
        for blob in tree.traverse(predicate=lambda item, d: item.type == "blob"):
            assert (blob.path, 0) in three_way_index.entries
            num_blobs += 1
        # END for each blob
        self.assertEqual(num_blobs, len(three_way_index.entries))
コード例 #2
0
ファイル: test_index.py プロジェクト: barry-scott/GitPython
    def test_index_merge_tree(self, rw_repo):
        # A bit out of place, but we need a different repo for this:
        self.assertNotEqual(self.rorepo, rw_repo)
        self.assertEqual(len(set((self.rorepo, self.rorepo, rw_repo, rw_repo))), 2)

        # SINGLE TREE MERGE
        # current index is at the (virtual) cur_commit
        next_commit = "4c39f9da792792d4e73fc3a5effde66576ae128c"
        parent_commit = rw_repo.head.commit.parents[0]
        manifest_key = IndexFile.entry_key('MANIFEST.in', 0)
        manifest_entry = rw_repo.index.entries[manifest_key]
        rw_repo.index.merge_tree(next_commit)
        # only one change should be recorded
        assert manifest_entry.binsha != rw_repo.index.entries[manifest_key].binsha

        rw_repo.index.reset(rw_repo.head)
        self.assertEqual(rw_repo.index.entries[manifest_key].binsha, manifest_entry.binsha)

        # FAKE MERGE
        #############
        # Add a change with a NULL sha that should conflict with next_commit. We
        # pretend there was a change, but we do not even bother adding a proper
        # sha for it ( which makes things faster of course )
        manifest_fake_entry = BaseIndexEntry((manifest_entry[0], b"\0" * 20, 0, manifest_entry[3]))
        # try write flag
        self._assert_entries(rw_repo.index.add([manifest_fake_entry], write=False))
        # add actually resolves the null-hex-sha for us as a feature, but we can
        # edit the index manually
        assert rw_repo.index.entries[manifest_key].binsha != Object.NULL_BIN_SHA
        # must operate on the same index for this ! Its a bit problematic as
        # it might confuse people
        index = rw_repo.index
        index.entries[manifest_key] = IndexEntry.from_base(manifest_fake_entry)
        index.write()
        self.assertEqual(rw_repo.index.entries[manifest_key].hexsha, Diff.NULL_HEX_SHA)

        # write an unchanged index ( just for the fun of it )
        rw_repo.index.write()

        # a three way merge would result in a conflict and fails as the command will
        # not overwrite any entries in our index and hence leave them unmerged. This is
        # mainly a protection feature as the current index is not yet in a tree
        self.failUnlessRaises(GitCommandError, index.merge_tree, next_commit, base=parent_commit)

        # the only way to get the merged entries is to safe the current index away into a tree,
        # which is like a temporary commit for us. This fails as well as the NULL sha deos not
        # have a corresponding object
        # NOTE: missing_ok is not a kwarg anymore, missing_ok is always true
        # self.failUnlessRaises(GitCommandError, index.write_tree)

        # if missing objects are okay, this would work though ( they are always okay now )
        # As we can't read back the tree with NULL_SHA, we rather set it to something else
        index.entries[manifest_key] = IndexEntry(manifest_entry[:1] + (hex_to_bin('f' * 40),) + manifest_entry[2:])
        tree = index.write_tree()

        # now make a proper three way merge with unmerged entries
        unmerged_tree = IndexFile.from_tree(rw_repo, parent_commit, tree, next_commit)
        unmerged_blobs = unmerged_tree.unmerged_blobs()
        self.assertEqual(len(unmerged_blobs), 1)
        self.assertEqual(list(unmerged_blobs.keys())[0], manifest_key[0])
コード例 #3
0
ファイル: test_docs.py プロジェクト: dbaxa/GitPython
    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", "*****@*****.**")
        committer = Actor("A committer", "*****@*****.**")
        # 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]
        ssh_executable = os.path.join(rw_dir, 'my_ssh_executable.sh')
        with repo.git.custom_environment(GIT_SSH=ssh_executable):
            # 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
コード例 #4
0
    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", "*****@*****.**")
        committer = Actor("A committer", "*****@*****.**")
        # 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
コード例 #5
0
    def test_index_merge_tree(self, rw_repo):
        # A bit out of place, but we need a different repo for this:
        self.assertNotEqual(self.rorepo, rw_repo)
        self.assertEqual(
            len(set((self.rorepo, self.rorepo, rw_repo, rw_repo))), 2)

        # SINGLE TREE MERGE
        # current index is at the (virtual) cur_commit
        next_commit = "4c39f9da792792d4e73fc3a5effde66576ae128c"
        parent_commit = rw_repo.head.commit.parents[0]
        manifest_key = IndexFile.entry_key('MANIFEST.in', 0)
        manifest_entry = rw_repo.index.entries[manifest_key]
        rw_repo.index.merge_tree(next_commit)
        # only one change should be recorded
        assert manifest_entry.binsha != rw_repo.index.entries[
            manifest_key].binsha

        rw_repo.index.reset(rw_repo.head)
        self.assertEqual(rw_repo.index.entries[manifest_key].binsha,
                         manifest_entry.binsha)

        # FAKE MERGE
        #############
        # Add a change with a NULL sha that should conflict with next_commit. We
        # pretend there was a change, but we do not even bother adding a proper
        # sha for it ( which makes things faster of course )
        manifest_fake_entry = BaseIndexEntry(
            (manifest_entry[0], b"\0" * 20, 0, manifest_entry[3]))
        # try write flag
        self._assert_entries(
            rw_repo.index.add([manifest_fake_entry], write=False))
        # add actually resolves the null-hex-sha for us as a feature, but we can
        # edit the index manually
        assert rw_repo.index.entries[manifest_key].binsha != Object.NULL_BIN_SHA
        # must operate on the same index for this ! Its a bit problematic as
        # it might confuse people
        index = rw_repo.index
        index.entries[manifest_key] = IndexEntry.from_base(manifest_fake_entry)
        index.write()
        self.assertEqual(rw_repo.index.entries[manifest_key].hexsha,
                         Diff.NULL_HEX_SHA)

        # write an unchanged index ( just for the fun of it )
        rw_repo.index.write()

        # a three way merge would result in a conflict and fails as the command will
        # not overwrite any entries in our index and hence leave them unmerged. This is
        # mainly a protection feature as the current index is not yet in a tree
        self.failUnlessRaises(GitCommandError,
                              index.merge_tree,
                              next_commit,
                              base=parent_commit)

        # the only way to get the merged entries is to safe the current index away into a tree,
        # which is like a temporary commit for us. This fails as well as the NULL sha deos not
        # have a corresponding object
        # NOTE: missing_ok is not a kwarg anymore, missing_ok is always true
        # self.failUnlessRaises(GitCommandError, index.write_tree)

        # if missing objects are okay, this would work though ( they are always okay now )
        # As we can't read back the tree with NULL_SHA, we rather set it to something else
        index.entries[manifest_key] = IndexEntry(manifest_entry[:1] +
                                                 (hex_to_bin('f' * 40), ) +
                                                 manifest_entry[2:])
        tree = index.write_tree()

        # now make a proper three way merge with unmerged entries
        unmerged_tree = IndexFile.from_tree(rw_repo, parent_commit, tree,
                                            next_commit)
        unmerged_blobs = unmerged_tree.unmerged_blobs()
        self.assertEqual(len(unmerged_blobs), 1)
        self.assertEqual(list(unmerged_blobs.keys())[0], manifest_key[0])