From 58e2157ad3aa9d75ef4abb90eb2d1f01fba0ba2b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 23:20:16 +0200 Subject: Added SymbolicReference and HEAD type to better represent these special types of references and allow special handling Head.reset now is an instance method of HEAD type Concatenated all reference specific tests into test_refs started to fix tests breaking now because of changed interface --- test/git/test_refs.py | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 test/git/test_refs.py (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py new file mode 100644 index 00000000..ece6bf3e --- /dev/null +++ b/test/git/test_refs.py @@ -0,0 +1,84 @@ +# test_refs.py +# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors +# +# This module is part of GitPython and is released under +# the BSD License: http://www.opensource.org/licenses/bsd-license.php + +from mock import * +from test.testlib import * +from git import * +import git.refs as refs +from git.objects.tag import TagObject +from itertools import chain + +class TestRefs(TestBase): + + def test_tag_base(self): + tag_object_refs = list() + for tag in self.rorepo.tags: + assert "refs/tags" in tag.path + assert tag.name + assert isinstance( tag.commit, Commit ) + if tag.tag is not None: + tag_object_refs.append( tag ) + tagobj = tag.tag + assert isinstance( tagobj, TagObject ) + assert tagobj.tag == tag.name + assert isinstance( tagobj.tagger, Actor ) + assert isinstance( tagobj.tagged_date, int ) + assert tagobj.message + # END if we have a tag object + # END for tag in repo-tags + assert tag_object_refs + assert isinstance(self.rorepo.tags['0.1.5'], TagReference) + + @patch_object(Git, '_call_process') + def test_ref_with_path_component(self, git): + git.return_value = fixture('for_each_ref_with_path_component') + head = self.rorepo.heads[0] + + assert_equal('refactoring/feature1', head.name) + assert_true(git.called) + + + def test_tags(self): + # tag refs can point to tag objects or to commits + s = set() + ref_count = 0 + for ref in chain(self.rorepo.tags, self.rorepo.heads): + ref_count += 1 + assert isinstance(ref, refs.Reference) + assert str(ref) == ref.name + assert repr(ref) + assert ref == ref + assert not ref != ref + s.add(ref) + # END for each ref + assert len(s) == ref_count + assert len(s|s) == ref_count + + def test_heads(self): + for head in self.rorepo.heads: + assert head.name + assert head.path + assert "refs/heads" in head.path + prev_object = head.object + cur_object = head.object + assert prev_object == cur_object # represent the same git object + assert prev_object is not cur_object # but are different instances + # END for each head + + @with_rw_repo('0.1.6') + def test_head_reset(self, rw_repo): + cur_head = rw_repo.head + new_head_commit = cur_head.ref.commit.parents[0] + reset_head = Head.reset(rw_repo, new_head_commit, index=True) # index only + assert reset_head.commit == new_head_commit + + self.failUnlessRaises(ValueError, Head.reset, rw_repo, new_head_commit, index=False, working_tree=True) + new_head_commit = new_head_commit.parents[0] + reset_head = Head.reset(rw_repo, new_head_commit, index=True, working_tree=True) # index + wt + assert reset_head.commit == new_head_commit + + # paths + Head.reset(rw_repo, new_head_commit, paths = "lib") -- cgit v1.2.3 From b7a5c05875a760c0bf83af6617c68061bda6cfc5 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 23:31:26 +0200 Subject: Adjusted tests to deal with API changes --- test/git/test_refs.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index ece6bf3e..0954d42d 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -72,13 +72,13 @@ class TestRefs(TestBase): def test_head_reset(self, rw_repo): cur_head = rw_repo.head new_head_commit = cur_head.ref.commit.parents[0] - reset_head = Head.reset(rw_repo, new_head_commit, index=True) # index only - assert reset_head.commit == new_head_commit + cur_head.reset(new_head_commit, index=True) # index only + assert cur_head.reference.commit == new_head_commit - self.failUnlessRaises(ValueError, Head.reset, rw_repo, new_head_commit, index=False, working_tree=True) + self.failUnlessRaises(ValueError, cur_head.reset, new_head_commit, index=False, working_tree=True) new_head_commit = new_head_commit.parents[0] - reset_head = Head.reset(rw_repo, new_head_commit, index=True, working_tree=True) # index + wt - assert reset_head.commit == new_head_commit + cur_head.reset(new_head_commit, index=True, working_tree=True) # index + wt + assert cur_head.reference.commit == new_head_commit # paths - Head.reset(rw_repo, new_head_commit, paths = "lib") + cur_head.reset(new_head_commit, paths = "lib") -- cgit v1.2.3 From d1bd99c0a376dec63f0f050aeb0c40664260da16 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 00:13:09 +0200 Subject: SymbolicReferences can now change they references safely as I think and well controlled, including test. Added commit method which will return the commit for detached symbolic refs or for normal symbolic refs which is quite convenient --- test/git/test_refs.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 0954d42d..1562310a 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -82,3 +82,29 @@ class TestRefs(TestBase): # paths cur_head.reset(new_head_commit, paths = "lib") + + + # now that we have a write write repo, change the HEAD reference - its + # like git-reset --soft + heads = rw_repo.heads + assert heads + for head in heads: + cur_head.reference = head + assert cur_head.reference == head + assert cur_head.commit == head.commit + assert not cur_head.is_detached + # END for each head + + # detach + cur_head.reference = heads[0].commit + assert cur_head.commit == heads[0].commit + assert cur_head.is_detached + self.failUnlessRaises(TypeError, getattr, cur_head, "reference") + + some_tag = rw_repo.tags[0] + cur_head.reference = some_tag + assert cur_head.is_detached + assert cur_head.commit == some_tag.commit + + # type check + self.failUnlessRaises(ValueError, setattr, cur_head, "reference", "that") -- cgit v1.2.3 From 2c23ca3cd9b9bbeaca1b79068dee1eae045be5b6 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 14:46:18 +0200 Subject: refs: added create, delete and rename methods where appropriate. Tests are marked, implementation is needed for most of them --- test/git/test_refs.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 1562310a..2665d93b 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -108,3 +108,11 @@ class TestRefs(TestBase): # type check self.failUnlessRaises(ValueError, setattr, cur_head, "reference", "that") + + + self.fail("head creation") + self.fail("head renaming") + self.fail("head removal") + self.fail("tag creation") + self.fail("tag deletion") + self.fail("remote deletion") -- cgit v1.2.3 From ddc5496506f0484e4f1331261aa8782c7e606bf2 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 15:22:07 +0200 Subject: Implemented head methods: create, delete, rename, including tests --- test/git/test_refs.py | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 2665d93b..ac213384 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -109,10 +109,39 @@ class TestRefs(TestBase): # type check self.failUnlessRaises(ValueError, setattr, cur_head, "reference", "that") + # head handling + commit = 'HEAD' + prev_head_commit = cur_head.commit + for count, new_name in enumerate(("my_new_head", "feature/feature1")): + actual_commit = commit+"^"*count + new_head = Head.create(rw_repo, new_name, actual_commit) + assert cur_head.commit == prev_head_commit + assert isinstance(new_head, Head) + # already exists + self.failUnlessRaises(GitCommandError, Head.create, rw_repo, new_name) + + # force it + new_head = Head.create(rw_repo, new_name, actual_commit, force=True) + old_path = new_head.path + old_name = new_head.name + + assert new_head.rename("hello").name == "hello" + assert new_head.rename("hello/world").name == "hello/world" + assert new_head.rename(old_name).name == old_name and new_head.path == old_path + + # rename with force + tmp_head = Head.create(rw_repo, "tmphead") + self.failUnlessRaises(GitCommandError, tmp_head.rename, new_head) + tmp_head.rename(new_head, force=True) + assert tmp_head == new_head and tmp_head.object == new_head.object + + Head.delete(rw_repo, tmp_head) + heads = rw_repo.heads + assert tmp_head not in heads and new_head not in heads + # force on deletion testing would be missing here, code looks okay though ;) + # END for each new head name + self.failUnlessRaises(TypeError, RemoteReference.create, rw_repo, "some_name") - self.fail("head creation") - self.fail("head renaming") - self.fail("head removal") self.fail("tag creation") self.fail("tag deletion") self.fail("remote deletion") -- cgit v1.2.3 From 1047b41e2e925617474e2e7c9927314f71ce7365 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 15:45:23 +0200 Subject: Added TagRefernce creation and deletion including tests Added RemoteReference deletion and test --- test/git/test_refs.py | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index ac213384..88e8a21a 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -142,6 +142,43 @@ class TestRefs(TestBase): # END for each new head name self.failUnlessRaises(TypeError, RemoteReference.create, rw_repo, "some_name") - self.fail("tag creation") - self.fail("tag deletion") - self.fail("remote deletion") + # tag ref + tag_name = "1.0.2" + light_tag = TagReference.create(rw_repo, tag_name) + self.failUnlessRaises(GitCommandError, TagReference.create, rw_repo, tag_name) + light_tag = TagReference.create(rw_repo, tag_name, "HEAD~1", force = True) + assert isinstance(light_tag, TagReference) + assert light_tag.name == tag_name + assert light_tag.commit == cur_head.commit.parents[0] + assert light_tag.tag is None + + # tag with tag object + other_tag_name = "releases/1.0.2RC" + msg = "my mighty tag\nsecond line" + obj_tag = TagReference.create(rw_repo, other_tag_name, message=msg) + assert isinstance(obj_tag, TagReference) + assert obj_tag.name == other_tag_name + assert obj_tag.commit == cur_head.commit + assert obj_tag.tag is not None + + TagReference.delete(rw_repo, light_tag, obj_tag) + tags = rw_repo.tags + assert light_tag not in tags and obj_tag not in tags + + # remote deletion + remote_refs_so_far = 0 + remotes = rw_repo.remotes + assert remotes + for remote in remotes: + refs = remote.refs + RemoteReference.delete(rw_repo, *refs) + remote_refs_so_far += len(refs) + # END for each ref to delete + assert remote_refs_so_far + + for remote in remotes: + # remotes without references throw + self.failUnlessRaises(AssertionError, getattr, remote, 'refs') + # END for each remote + + self.fail("set commit using ref.commit = that") -- cgit v1.2.3 From 9b9776e88f7abb59cebac8733c04cccf6eee1c60 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 16:07:45 +0200 Subject: Refs can now set the reference they are pointing to in a controlled fashion by writing their ref file directly --- test/git/test_refs.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 88e8a21a..696b95c7 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -181,4 +181,20 @@ class TestRefs(TestBase): self.failUnlessRaises(AssertionError, getattr, remote, 'refs') # END for each remote - self.fail("set commit using ref.commit = that") + # change where the active head points to + if cur_head.is_detached: + cur_head.reference = rw_repo.heads[0] + + head = cur_head.reference + old_commit = head.commit + head.commit = old_commit.parents[0] + assert head.commit == old_commit.parents[0] + assert head.commit == cur_head.commit + head.commit = old_commit + + # setting a non-commit as commit fails, but succeeds as object + head_tree = head.commit.tree + self.failUnlessRaises(TypeError, setattr, head, 'commit', head_tree) + assert head.commit == old_commit # and the ref did not change + head.object = head_tree + assert head.object == head_tree -- cgit v1.2.3 From 0725af77afc619cdfbe3cec727187e442cceaf97 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 26 Oct 2009 11:21:59 +0100 Subject: refs.SymoblicRef: implemented direcft setting of the symbolic references commit, which possibly dereferences to the respective head --- test/git/test_refs.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 696b95c7..979165ef 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -198,3 +198,21 @@ class TestRefs(TestBase): assert head.commit == old_commit # and the ref did not change head.object = head_tree assert head.object == head_tree + self.failUnlessRaises(TypeError, getattr, head, 'commit') # object is a tree, not a commit + + # set the commit directly using the head. This would never detach the head + assert not cur_head.is_detached + head.object = old_commit + cur_head.reference = head.commit + assert cur_head.is_detached + parent_commit = head.commit.parents[0] + assert cur_head.is_detached + cur_head.commit = parent_commit + assert cur_head.is_detached and cur_head.commit == parent_commit + + cur_head.reference = head + assert not cur_head.is_detached + cur_head.commit = parent_commit + assert not cur_head.is_detached + assert head.commit == parent_commit + -- cgit v1.2.3 From 685d6e651197d54e9a3e36f5adbadd4d21f4c7e5 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 18:41:35 +0100 Subject: Added repo.refs for completeness (as remote.refs is there as well and quite nice to use) --- test/git/test_refs.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 979165ef..0a70af1f 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -68,6 +68,12 @@ class TestRefs(TestBase): assert prev_object is not cur_object # but are different instances # END for each head + def test_refs(self): + types_found = set() + for ref in self.rorepo.refs: + types_found.add(type(ref)) + assert len(types_found) == 3 + @with_rw_repo('0.1.6') def test_head_reset(self, rw_repo): cur_head = rw_repo.head -- cgit v1.2.3 From 572ace094208c28ab1a8641aedb038456d13f70b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 17:44:13 +0100 Subject: Now using git-update-ref and git-symbolic-ref to update references with reflog support. This should be manually implemented though for more performance, what it does is relatively easy --- test/git/test_refs.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 0a70af1f..f7f4f71a 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -200,11 +200,9 @@ class TestRefs(TestBase): # setting a non-commit as commit fails, but succeeds as object head_tree = head.commit.tree - self.failUnlessRaises(TypeError, setattr, head, 'commit', head_tree) + self.failUnlessRaises(GitCommandError, setattr, head, 'commit', head_tree) assert head.commit == old_commit # and the ref did not change - head.object = head_tree - assert head.object == head_tree - self.failUnlessRaises(TypeError, getattr, head, 'commit') # object is a tree, not a commit + self.failUnlessRaises(GitCommandError, setattr, head, 'object', head_tree) # set the commit directly using the head. This would never detach the head assert not cur_head.is_detached -- cgit v1.2.3 From 43ab2afba68fd0e1b5d138ed99ffc788dc685e36 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 20:59:24 +0100 Subject: refs: iter_items now imlemented natively for additional performance. We did not implement the crazy sorting feature found in git-for-each-ref though --- test/git/test_refs.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index f7f4f71a..6b3c2840 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -32,15 +32,6 @@ class TestRefs(TestBase): assert tag_object_refs assert isinstance(self.rorepo.tags['0.1.5'], TagReference) - @patch_object(Git, '_call_process') - def test_ref_with_path_component(self, git): - git.return_value = fixture('for_each_ref_with_path_component') - head = self.rorepo.heads[0] - - assert_equal('refactoring/feature1', head.name) - assert_true(git.called) - - def test_tags(self): # tag refs can point to tag objects or to commits s = set() @@ -220,3 +211,8 @@ class TestRefs(TestBase): assert not cur_head.is_detached assert head.commit == parent_commit + # test ref listing - assure we have packed refs + rw_repo.git.pack_refs(all=True) + assert rw_repo.heads + assert rw_repo.tags + -- cgit v1.2.3 From ace1fed6321bb8dd6d38b2f58d7cf815fa16db7a Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 4 Nov 2009 19:36:29 +0100 Subject: head.checkout method added including test --- test/git/test_refs.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'test/git/test_refs.py') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 6b3c2840..32a6de1c 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -211,8 +211,29 @@ class TestRefs(TestBase): assert not cur_head.is_detached assert head.commit == parent_commit + # test checkout + active_branch = rw_repo.active_branch + for head in rw_repo.heads: + checked_out_head = head.checkout() + assert checked_out_head == head + # END for each head to checkout + + # checkout with branch creation + new_head = active_branch.checkout(b="new_head") + assert active_branch != rw_repo.active_branch + assert new_head == rw_repo.active_branch + + # checkout with force has we have a change + # clear file + open(new_head.commit.tree.blobs[-1].abspath,'w').close() + assert len(new_head.commit.diff(None)) == 1 + + # create a new branch that is likely to touch the file we changed + far_away_head = rw_repo.create_head("far_head",'HEAD~100') + self.failUnlessRaises(GitCommandError, far_away_head.checkout) + assert active_branch == active_branch.checkout(force=True) + # test ref listing - assure we have packed refs rw_repo.git.pack_refs(all=True) assert rw_repo.heads assert rw_repo.tags - -- cgit v1.2.3