diff options
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | doc/tutorial.rst | 5 | ||||
-rw-r--r-- | lib/git/refs.py | 34 | ||||
-rw-r--r-- | test/git/test_refs.py | 23 |
4 files changed, 59 insertions, 5 deletions
@@ -110,8 +110,6 @@ Repo * Figure out how to implement a proper merge API. It should be index based, but provide all necessary information to the ones willing to ask for it. The index implementation actually provides this already, but some real use-cases would be great to have a least. -* repo.checkout should be added that does everything HEAD.reset does, but in addition - it allows to checkout heads beforehand, hence its more like a repo.head.reference = other_head. Submodules diff --git a/doc/tutorial.rst b/doc/tutorial.rst index f48aceb0..695e9812 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -351,7 +351,10 @@ is the following one. The previous approach would brutally overwrite the user's changes in the working copy and index though and is less sophisticated than a git-checkout for instance which -generally prevents you from destroying your work. +generally prevents you from destroying your work. Use the safer approach as follows: + + >>> repo.heads.master.checkout() # checkout the branch using git-checkout + >>> repo.heads.other_branch.checkout() Using git directly ****************** diff --git a/lib/git/refs.py b/lib/git/refs.py index 1900c6ce..5b94ea07 100644 --- a/lib/git/refs.py +++ b/lib/git/refs.py @@ -517,7 +517,39 @@ class Head(Reference): self.path = "%s/%s" % (self._common_path_default, new_path) return self - + def checkout(self, force=False, **kwargs): + """ + Checkout this head by setting the HEAD to this reference, by updating the index + to reflect the tree we point to and by updating the working tree to reflect + the latest index. + + The command will fail if changed working tree files would be overwritten. + + ``force`` + If True, changes to the index and the working tree will be discarded. + If False, GitCommandError will be raised in that situation. + + ``**kwargs`` + Additional keyword arguments to be passed to git checkout, i.e. + b='new_branch' to create a new branch at the given spot. + + Returns + The active branch after the checkout operation, usually self unless + a new branch has been created. + + Note + By default it is only allowed to checkout heads - everything else + will leave the HEAD detached which is allowed and possible, but remains + a special state that some tools might not be able to handle. + """ + args = list() + kwargs['f'] = force + if kwargs['f'] == False: + kwargs.pop('f') + + self.repo.git.checkout(self, **kwargs) + return self.repo.active_branch + class TagReference(Reference): """ 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 - |