Skip to content

Commit 8284957

Browse files
committed
ORIG_HEAD handling is now implemented in the ref-class itself, instead of being a special case of the commit method; includes tests
util: Fixed iterable lists, which broke due to an incorrectly implemented __contains__ method
1 parent 7a320ab commit 8284957

File tree

4 files changed

+76
-17
lines changed

4 files changed

+76
-17
lines changed

lib/git/objects/commit.py

-3
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,6 @@ def create_from_tree(cls, repo, tree, message, parent_commits=None, head=False):
369369
# as well ...
370370
import git.refs
371371
try:
372-
cur_commit = repo.head.commit
373-
# Adjust the original head reference - force it
374-
git.refs.SymbolicReference.create(repo, 'ORIG_HEAD', cur_commit, force=True)
375372
repo.head.commit = new_commit
376373
except ValueError:
377374
# head is not yet set to the ref our HEAD points to

lib/git/refs.py

+45-6
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,30 @@ def _set_reference(self, ref):
224224
# END end try string
225225
# END try commit attribute
226226

227+
# maintain the orig-head if we are currently checked-out
228+
head = HEAD(self.repo)
229+
try:
230+
if head.ref == self:
231+
try:
232+
# TODO: implement this atomically, if we fail below, orig_head is at an incorrect spot
233+
# Enforce the creation of ORIG_HEAD
234+
SymbolicReference.create(self.repo, head.orig_head().name, self.commit, force=True)
235+
except ValueError:
236+
pass
237+
#END exception handling
238+
# END if we are checked-out
239+
except TypeError:
240+
pass
241+
# END handle detached heads
242+
227243
# if we are writing a ref, use symbolic ref to get the reflog and more
228244
# checking
229-
# Otherwise we detach it and have to do it manually
245+
# Otherwise we detach it and have to do it manually. Besides, this works
246+
# recursively automaitcally, but should be replaced with a python implementation
247+
# soon
230248
if write_value.startswith('ref:'):
231249
self.repo.git.symbolic_ref(self.path, write_value[5:])
232-
return
250+
return
233251
# END non-detached handling
234252

235253
path = self._abs_path()
@@ -243,10 +261,10 @@ def _set_reference(self, ref):
243261
finally:
244262
fp.close()
245263
# END writing
246-
247-
reference = property(_get_reference, _set_reference, doc="Returns the Reference we point to")
248264

249-
# alias
265+
266+
# aliased reference
267+
reference = property(_get_reference, _set_reference, doc="Returns the Reference we point to")
250268
ref = reference
251269

252270
def is_valid(self):
@@ -553,7 +571,6 @@ def _set_object(self, ref):
553571
554572
:note:
555573
TypeChecking is done by the git command"""
556-
# check for existence, touch it if required
557574
abs_path = self._abs_path()
558575
existed = True
559576
if not isfile(abs_path):
@@ -618,13 +635,35 @@ class HEAD(SymbolicReference):
618635
"""Special case of a Symbolic Reference as it represents the repository's
619636
HEAD reference."""
620637
_HEAD_NAME = 'HEAD'
638+
_ORIG_HEAD_NAME = 'ORIG_HEAD'
621639
__slots__ = tuple()
622640

623641
def __init__(self, repo, path=_HEAD_NAME):
624642
if path != self._HEAD_NAME:
625643
raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, path))
626644
super(HEAD, self).__init__(repo, path)
627645

646+
def orig_head(self):
647+
""":return: SymbolicReference pointing at the ORIG_HEAD, which is maintained
648+
to contain the previous value of HEAD"""
649+
return SymbolicReference(self.repo, self._ORIG_HEAD_NAME)
650+
651+
def _set_reference(self, ref):
652+
"""If someone changes the reference through us, we must manually update
653+
the ORIG_HEAD if we are detached. The underlying implementation can only
654+
handle un-detached heads as it has to check whether the current head
655+
is the checked-out one"""
656+
if self.is_detached:
657+
prev_commit = self.commit
658+
super(HEAD, self)._set_reference(ref)
659+
SymbolicReference.create(self.repo, self._ORIG_HEAD_NAME, prev_commit, force=True)
660+
else:
661+
super(HEAD, self)._set_reference(ref)
662+
# END handle detached mode
663+
664+
# aliased reference
665+
reference = property(SymbolicReference._get_reference, _set_reference, doc="Returns the Reference we point to")
666+
ref = reference
628667

629668
def reset(self, commit='HEAD', index=True, working_tree = False,
630669
paths=None, **kwargs):

lib/git/util.py

-8
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,6 @@ def __getitem__(self, index):
317317
except AttributeError:
318318
raise IndexError( "No item found with id %r" % (self._prefix + index) )
319319

320-
def __contains__(self, item):
321-
try:
322-
self[item]
323-
return True
324-
except IndexError:
325-
return False
326-
# END handle exception
327-
328320

329321
class Iterable(object):
330322
"""Defines an interface for iterable items which is to assure a uniform

test/git/test_refs.py

+31
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,37 @@ def test_heads(self, rwrepo):
9292
assert head.tracking_branch() is None
9393
# END for each head
9494

95+
# verify ORIG_HEAD gets set for detached heads
96+
head = rwrepo.head
97+
orig_head = head.orig_head()
98+
cur_head = head.ref
99+
cur_commit = cur_head.commit
100+
pcommit = cur_head.commit.parents[0].parents[0]
101+
head.ref = pcommit # detach head
102+
assert orig_head.commit == cur_commit
103+
104+
# even if we set it through its reference - chaning the ref
105+
# will adjust the orig_head, which still points to cur_commit
106+
head.ref = cur_head
107+
assert orig_head.commit == pcommit
108+
assert head.commit == cur_commit == cur_head.commit
109+
110+
cur_head.commit = pcommit
111+
assert head.commit == pcommit
112+
assert orig_head.commit == cur_commit
113+
114+
# with automatic dereferencing
115+
head.commit = cur_commit
116+
assert orig_head.commit == pcommit
117+
118+
# changing branches which are not checked out doesn't affect the ORIG_HEAD
119+
other_head = Head.create(rwrepo, 'mynewhead', pcommit)
120+
assert other_head.commit == pcommit
121+
assert orig_head.commit == pcommit
122+
other_head.commit = pcommit.parents[0]
123+
assert orig_head.commit == pcommit
124+
125+
95126
def test_refs(self):
96127
types_found = set()
97128
for ref in self.rorepo.refs:

0 commit comments

Comments
 (0)