diff options
author | Sebastian Thiel <byronimo@gmail.com> | 2009-10-23 15:22:07 +0200 |
---|---|---|
committer | Sebastian Thiel <byronimo@gmail.com> | 2009-10-23 15:22:07 +0200 |
commit | ddc5496506f0484e4f1331261aa8782c7e606bf2 (patch) | |
tree | 91c805398899b2671ac887149b0193a74e7a8628 | |
parent | 2c23ca3cd9b9bbeaca1b79068dee1eae045be5b6 (diff) | |
download | gitpython-ddc5496506f0484e4f1331261aa8782c7e606bf2.tar.gz |
Implemented head methods: create, delete, rename, including tests
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | lib/git/refs.py | 34 | ||||
-rw-r--r-- | test/git/test_refs.py | 35 |
3 files changed, 56 insertions, 17 deletions
@@ -73,7 +73,7 @@ Refs * Ability to create new heads and tags in the Repository ( but using the respective Reference Type ), i.e. Head.create(repo, name, commit = 'HEAD') or TagReference.create(repo, name -* Ability to rename references and tags +* Ability to rename references and tagsre * Ability to remove references and tags * Ability to checkout a reference - * Check whether we are the active reference HEAD.commit == self.commit @@ -83,6 +83,8 @@ Remote * 'push' method needs a test, a true test repository is required though, a fork of a fork would do :)! * Fetch should return heads that where updated, pull as well. +* Creation and deletion methods for references should be part of the interface, allowing + repo.create_head(...) instaed of Head.create(repo, ...). Its a convenience thing, clearly Repo ---- diff --git a/lib/git/refs.py b/lib/git/refs.py index 29468d1c..7b58f215 100644 --- a/lib/git/refs.py +++ b/lib/git/refs.py @@ -19,7 +19,7 @@ class Reference(LazyMixin, Iterable): _common_path_default = "refs" _id_attribute_ = "name" - def __init__(self, repo, path, object = None): + def __init__(self, repo, path): """ Initialize this instance ``repo`` @@ -29,16 +29,12 @@ class Reference(LazyMixin, Iterable): Path relative to the .git/ directory pointing to the ref in question, i.e. refs/heads/master - ``object`` - Object instance, will be retrieved on demand if None """ if not path.startswith(self._common_path_default): raise ValueError("Cannot instantiate %s Reference from path %s" % ( self.__class__.__name__, path )) self.repo = repo self.path = path - if object is not None: - self.object = object def __str__(self): return self.name @@ -386,7 +382,7 @@ class Head(Reference): _common_path_default = "refs/heads" @classmethod - def create(cls, repo, path, commit=HEAD(), **kwargs ): + def create(cls, repo, path, commit='HEAD', force=False, **kwargs ): """ Create a new head. ``repo`` @@ -399,11 +395,13 @@ class Head(Reference): ``commit`` Commit to which the new head should point, defaults to the current HEAD + + ``force`` + if True, force creation even if branch with that name already exists. ``**kwargs`` Additional keyword arguments to be passed to git-branch, i.e. - track, no-track, l, f to force creation even if branch with that - name already exists. + track, no-track, l Returns Newly created Head @@ -411,18 +409,28 @@ class Head(Reference): Note This does not alter the current HEAD, index or Working Tree """ - raise NotImplementedError("todo") + if cls is not Head: + raise TypeError("Only Heads can be created explicitly, not objects of type %s" % cls.__name__) + + args = ( path, commit ) + if force: + kwargs['f'] = True + + repo.git.branch(*args, **kwargs) + return cls(repo, "%s/%s" % ( cls._common_path_default, path)) @classmethod - def delete(cls, repo, *heads, force=False): + def delete(cls, repo, *heads, **kwargs): """ Delete the given heads ``force`` If True, the heads will be deleted even if they are not yet merged into - the main development stream + the main development stream. + Default False """ + force = kwargs.get("force", False) flag = "-d" if force: flag = "-D" @@ -448,7 +456,7 @@ class Head(Reference): if force: flag = "-M" - self.repo.git.branch(flag, new_path) + self.repo.git.branch(flag, self, new_path) self.path = "%s/%s" % (self._common_path_default, new_path) return self @@ -568,7 +576,7 @@ class RemoteReference(Head): return '/'.join(tokens[3:]) @classmethod - def delete(cls, repo, *remotes): + def delete(cls, repo, *remotes, **kwargs): """ Delete the given remote references. """ 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") |