summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--refs/reference.py30
-rw-r--r--refs/symbolic.py14
-rw-r--r--test/test_refs.py73
3 files changed, 82 insertions, 35 deletions
diff --git a/refs/reference.py b/refs/reference.py
index e7cdfdee..c44ebf00 100644
--- a/refs/reference.py
+++ b/refs/reference.py
@@ -37,6 +37,36 @@ class Reference(SymbolicReference, LazyMixin, Iterable):
def __str__(self):
return self.name
+ def set_object(self, object, msg = None):
+ """Special version which checks if the head-log needs an update as well"""
+ oldbinsha = None
+ if msg is not None:
+ head = self.repo.head
+ if not head.is_detached and head.ref == self:
+ oldbinsha = self.commit.binsha
+ #END handle commit retrieval
+ #END handle message is set
+
+ super(Reference, self).set_object(object, msg)
+
+ if oldbinsha is not None:
+ # /* from refs.c in git-source
+ # * Special hack: If a branch is updated directly and HEAD
+ # * points to it (may happen on the remote side of a push
+ # * for example) then logically the HEAD reflog should be
+ # * updated too.
+ # * A generic solution implies reverse symref information,
+ # * but finding all symrefs pointing to the given branch
+ # * would be rather costly for this rare event (the direct
+ # * update of a branch) to be worth it. So let's cheat and
+ # * check with HEAD only which should cover 99% of all usage
+ # * scenarios (even 100% of the default ones).
+ # */
+ self.repo.head.log_append(oldbinsha, msg)
+ #END check if the head
+
+ # NOTE: Don't have to overwrite properties as the will only work without a the log
+
@property
def name(self):
""":return: (shortest) Name of this reference - it may contain path components"""
diff --git a/refs/symbolic.py b/refs/symbolic.py
index 83dbafd2..cdd6158a 100644
--- a/refs/symbolic.py
+++ b/refs/symbolic.py
@@ -175,7 +175,8 @@ class SymbolicReference(object):
def set_commit(self, commit, msg = None):
"""As set_object, but restricts the type of object to be a Commit
:raise ValueError: If commit is not a Commit object or doesn't point to
- a commit"""
+ a commit
+ :return: self"""
# check the type - assume the best if it is a base-string
invalid_type = False
if isinstance(commit, Object):
@@ -197,6 +198,8 @@ class SymbolicReference(object):
# we leave strings to the rev-parse method below
self.set_object(commit, msg)
+ return self
+
def set_object(self, object, msg = None):
"""Set the object we point to, possibly dereference our symbolic reference first.
@@ -206,7 +209,8 @@ class SymbolicReference(object):
will be dereferenced beforehand to obtain the object they point to
:param msg: If not None, the message will be used in the reflog entry to be
written. Otherwise the reflog is not altered
- :note: plain SymbolicReferences may not actually point to objects by convention"""
+ :note: plain SymbolicReferences may not actually point to objects by convention
+ :return: self"""
if isinstance(object, SymbolicReference):
object = object.object
#END resolve references
@@ -222,7 +226,7 @@ class SymbolicReference(object):
return self.set_reference(object, msg)
# set the commit on our reference
- self._get_reference().set_object(object, msg)
+ return self._get_reference().set_object(object, msg)
commit = property(_get_commit, set_commit, doc="Query or set commits directly")
object = property(_get_object, set_object, doc="Return the object our ref currently refers to")
@@ -250,6 +254,8 @@ class SymbolicReference(object):
The previous commit of the entry will be the commit we point to now.
See also: log_append()
+
+ :return: self
:note: This symbolic reference will not be dereferenced. For that, see
``set_object(...)``"""
write_value = None
@@ -297,6 +303,8 @@ class SymbolicReference(object):
self.log_append(oldbinsha, msg)
#END handle reflog
+ return self
+
# aliased reference
reference = property(_get_reference, set_reference, doc="Returns the Reference we point to")
diff --git a/test/test_refs.py b/test/test_refs.py
index fefce6be..3ad4dad2 100644
--- a/test/test_refs.py
+++ b/test/test_refs.py
@@ -96,38 +96,46 @@ class TestRefs(TestBase):
# END for each head
# verify REFLOG gets altered
- if False:
- head = rwrepo.head
- orig_head = head.orig_head()
- cur_head = head.ref
- cur_commit = cur_head.commit
- pcommit = cur_head.commit.parents[0].parents[0]
- head.ref = pcommit # detach head
- assert orig_head.commit == cur_commit
-
- # even if we set it through its reference - chaning the ref
- # will adjust the orig_head, which still points to cur_commit
- head.ref = cur_head
- assert orig_head.commit == pcommit
- assert head.commit == cur_commit == cur_head.commit
-
- cur_head.commit = pcommit
- assert head.commit == pcommit
- assert orig_head.commit == cur_commit
-
- # with automatic dereferencing
- head.commit = cur_commit
- assert orig_head.commit == pcommit
-
- # changing branches which are not checked out doesn't affect the ORIG_HEAD
- other_head = Head.create(rwrepo, 'mynewhead', pcommit)
- assert other_head.commit == pcommit
- assert orig_head.commit == pcommit
- other_head.commit = pcommit.parents[0]
- assert orig_head.commit == pcommit
-
- # TODO: Need changing a ref changes HEAD reflog as well if it pointed to it
-
+ head = rwrepo.head
+ cur_head = head.ref
+ cur_commit = cur_head.commit
+ pcommit = cur_head.commit.parents[0].parents[0]
+ hlog_len = len(head.log())
+ blog_len = len(cur_head.log())
+ head.set_reference(pcommit, 'detached head')
+ # one new log-entry
+ thlog = head.log()
+ assert len(thlog) == hlog_len + 1
+ assert thlog[-1].oldhexsha == cur_commit.hexsha
+ assert thlog[-1].newhexsha == pcommit.hexsha
+
+ # the ref didn't change though
+ assert len(cur_head.log()) == blog_len
+
+ # head changes once again, cur_head doesn't change
+ head.set_reference(cur_head, 'reattach head')
+ assert len(head.log()) == hlog_len+2
+ assert len(cur_head.log()) == blog_len
+
+ # adjusting the head-ref also adjust the head, so both reflogs are
+ # altered
+ cur_head.set_commit(pcommit, 'changing commit')
+ assert len(cur_head.log()) == blog_len+1
+ assert len(head.log()) == hlog_len+3
+
+
+ # with automatic dereferencing
+ head.set_commit(cur_commit, 'change commit once again')
+ assert len(head.log()) == hlog_len+4
+ assert len(cur_head.log()) == blog_len+2
+
+ # a new branch has just a single entry
+ other_head = Head.create(rwrepo, 'mynewhead', pcommit, msg='new head created')
+ log = other_head.log()
+ assert len(log) == 1
+ assert log[0].oldhexsha == pcommit.NULL_HEX_SHA
+ assert log[0].newhexsha == pcommit.hexsha
+
def test_refs(self):
types_found = set()
@@ -509,4 +517,5 @@ class TestRefs(TestBase):
# delete deletes the reflog
# create creates a new entry
# set_reference and set_commit and set_object use the reflog if message is given
+ # if there is no actual head-change, don't do anything
self.fail()