summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2009-12-03 22:11:34 +0100
committerSebastian Thiel <byronimo@gmail.com>2009-12-03 22:11:34 +0100
commit12276fedec49c855401262f0929f088ebf33d2cf (patch)
treefd1adacb07ff59d279936dffc9c879bdecb82360
parent7d00fa4f6cad398250ce868cef34357b45abaad3 (diff)
downloadgitpython-12276fedec49c855401262f0929f088ebf33d2cf.tar.gz
refs: Implemented low-level (Symbolic)Reference renaming as some references cannot be reamed using the git-branch command if they are not in refs/heads, that is in a non-standard refs folder
-rw-r--r--lib/git/refs.py47
-rw-r--r--lib/git/utils.py14
-rw-r--r--test/git/test_refs.py24
3 files changed, 70 insertions, 15 deletions
diff --git a/lib/git/refs.py b/lib/git/refs.py
index f826691d..0b8b2a98 100644
--- a/lib/git/refs.py
+++ b/lib/git/refs.py
@@ -309,6 +309,47 @@ class SymbolicReference(object):
This does not alter the current HEAD, index or Working Tree
"""
return cls._create(repo, path, False, reference, force)
+
+ def rename(self, new_path, force=False):
+ """
+ Rename self to a new path
+
+ ``new_path``
+ Either a simple name or a full path, i.e. new_name or features/new_name.
+ The prefix refs/ is implied for references and will be set as needed.
+ In case this is a symbolic ref, there is no implied prefix
+
+ ``force``
+ If True, the rename will succeed even if a head with the target name
+ already exists. It will be overwritten in that case
+
+ Returns
+ self
+
+ Raises OSError:
+ In case a file at path with that name already exists
+ """
+ new_path = self._to_full_path(self.repo, new_path)
+ if self.path == new_path:
+ return self
+
+ new_abs_path = os.path.join(self.repo.git_dir, new_path)
+ if os.path.isfile(new_abs_path):
+ if not force:
+ raise OSError("File at path %r already exists" % new_abs_path)
+ os.remove(new_abs_path)
+ # END handle existing target file
+
+ dirname = os.path.dirname(new_abs_path)
+ if not os.path.isdir(dirname):
+ os.makedirs(dirname)
+ # END create directory
+
+ cur_abs_path = os.path.join(self.repo.git_dir, self.path)
+ os.rename(cur_abs_path, new_abs_path)
+ self.path = new_path
+
+ return self
class Reference(SymbolicReference, LazyMixin, Iterable):
@@ -330,7 +371,7 @@ class Reference(SymbolicReference, LazyMixin, Iterable):
refs/heads/master
"""
- if not path.startswith(self._common_path_default):
+ if not path.startswith(self._common_path_default+'/'):
raise ValueError("Cannot instantiate %s from path %s" % ( self.__class__.__name__, path ))
super(Reference, self).__init__(repo, path)
@@ -472,6 +513,7 @@ class Reference(SymbolicReference, LazyMixin, Iterable):
"""
return cls._create(repo, path, True, commit, force)
+
class HEAD(SymbolicReference):
"""
@@ -623,6 +665,9 @@ class Head(Reference):
Returns
self
+
+ Note
+ respects the ref log as git commands are used
"""
flag = "-m"
if force:
diff --git a/lib/git/utils.py b/lib/git/utils.py
index 433f96d5..27ce0804 100644
--- a/lib/git/utils.py
+++ b/lib/git/utils.py
@@ -362,18 +362,4 @@ class Iterable(object):
"""
raise NotImplementedError("To be implemented by Subclass")
-def needs_working_tree(func):
- """
- Decorator assuring the wrapped method may only run if the repository has a
- working tree, hence it is not bare.
- """
- def check_default_index(self, *args, **kwargs):
- if self.repo.working_tree_dir is None:
- raise AssertionError( "Cannot call %r bare git repositories" % func.__name__ )
- return func(self, *args, **kwargs)
- # END wrpaper method
-
- check_default_index.__name__ = func.__name__
- return check_default_index
-
diff --git a/test/git/test_refs.py b/test/git/test_refs.py
index 13297512..aee9b706 100644
--- a/test/git/test_refs.py
+++ b/test/git/test_refs.py
@@ -255,6 +255,21 @@ class TestRefs(TestBase):
assert ref.path == full_ref
assert ref.object == rw_repo.head.commit.parents[0]
+ # rename it
+ orig_obj = ref.object
+ for name in ('refs/absname', 'rela_name', 'feature/rela_name'):
+ ref_new_name = ref.rename(name)
+ assert isinstance(ref_new_name, Reference)
+ assert name in ref_new_name.path
+ assert ref_new_name.object == orig_obj
+ assert ref_new_name == ref
+ # END for each name type
+ # exists, fail unless we force
+ ex_ref_path = far_away_head.path
+ self.failUnlessRaises(OSError, ref.rename, ex_ref_path)
+ assert ref.rename(ex_ref_path, force=True).path == ex_ref_path and ref.object == orig_obj
+ assert ref.rename(ref.path).path == ex_ref_path # rename to same name
+
# create symbolic refs
symref_path = "symrefs/sym"
symref = SymbolicReference.create(rw_repo, symref_path, cur_head.reference)
@@ -279,6 +294,15 @@ class TestRefs(TestBase):
assert os.path.isfile(symbol_ref_abspath)
assert symref.commit == new_head.commit
+ for name in ('absname','folder/rela_name'):
+ symref_new_name = symref.rename(name)
+ assert isinstance(symref_new_name, SymbolicReference)
+ assert name in symref_new_name.path
+ assert symref_new_name.reference == new_head
+ assert symref_new_name == symref
+ assert not symref.is_detached
+ # END for each ref
+
# test ref listing - assure we have packed refs
rw_repo.git.pack_refs(all=True, prune=True)
heads = rw_repo.heads