Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit aaeb986

Browse files
committed
SymbolicReferences can now be at any path within the repository, there is no restriction anymore.
Added a test to assure the git commands can handle it
1 parent 9c92df6 commit aaeb986

File tree

4 files changed

+48
-27
lines changed

4 files changed

+48
-27
lines changed

lib/git/cmd.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ def _parse_object_header(self, header_line):
344344
"""
345345
tokens = header_line.split()
346346
if len(tokens) != 3:
347-
raise ValueError("SHA named %s could not be resolved" % tokens[0] )
347+
raise ValueError("SHA named %s could not be resolved, git returned: %r" % (tokens[0], header_line.strip()) )
348348
if len(tokens[0]) != 40:
349349
raise ValueError("Failed to parse header: %r" % header_line)
350350
return (tokens[0], tokens[1], int(tokens[2]))

lib/git/index.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,10 +1039,6 @@ def checkout(self, paths=None, force=False, fprogress=lambda *args: None, **kwar
10391039
If None, all paths in the index will be checked out. Otherwise an iterable
10401040
of relative or absolute paths or a single path pointing to files or directories
10411041
in the index is expected.
1042-
The command will raise of files or directories do not exist in the index
1043-
( as opposed to the original git command who ignores them ). Additionally
1044-
this command allows to checkout directories which is an extension to git-update-index.
1045-
10461042
10471043
``force``
10481044
If True, existing files will be overwritten even if they contain local modifications.
@@ -1064,6 +1060,8 @@ def checkout(self, paths=None, force=False, fprogress=lambda *args: None, **kwar
10641060
Raise CheckoutError
10651061
If at least one file failed to be checked out. This is a summary,
10661062
hence it will checkout as many files as it can anyway.
1063+
If one of files or directories do not exist in the index
1064+
( as opposed to the original git command who ignores them ).
10671065
Raise GitCommandError if error lines could not be parsed - this truly is
10681066
an exceptional state
10691067
"""

lib/git/refs.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def __repr__(self):
4343
return '<git.%s "%s">' % (self.__class__.__name__, self.path)
4444

4545
def __eq__(self, other):
46-
return self.path == other.path and self.object == other.object
46+
return self.path == other.path
4747

4848
def __ne__(self, other):
4949
return not ( self == other )
@@ -203,34 +203,29 @@ class SymbolicReference(object):
203203
204204
A typical example for a symbolic reference is HEAD.
205205
"""
206-
__slots__ = ("repo", "name")
206+
__slots__ = ("repo", "path")
207207

208-
def __init__(self, repo, name):
209-
if '/' in name:
210-
# NOTE: Actually they can be looking like ordinary refs. Theoretically we handle this
211-
# case incorrectly
212-
raise ValueError("SymbolicReferences are not located within a directory, got %s" % name)
213-
# END error handling
208+
def __init__(self, repo, path):
214209
self.repo = repo
215-
self.name = name
210+
self.path = path
216211

217212
def __str__(self):
218-
return self.name
213+
return self.path
219214

220215
def __repr__(self):
221-
return '<git.%s "%s">' % (self.__class__.__name__, self.name)
216+
return '<git.%s "%s">' % (self.__class__.__name__, self.path)
222217

223218
def __eq__(self, other):
224-
return self.name == other.name
219+
return self.path == other.path
225220

226221
def __ne__(self, other):
227222
return not ( self == other )
228223

229224
def __hash__(self):
230-
return hash(self.name)
225+
return hash(self.path)
231226

232227
def _get_path(self):
233-
return join_path_native(self.repo.path, self.name)
228+
return join_path_native(self.repo.path, self.path)
234229

235230
def _get_commit(self):
236231
"""
@@ -311,7 +306,7 @@ def _set_reference(self, ref):
311306
# checking
312307
# Otherwise we detach it and have to do it manually
313308
if write_value.startswith('ref:'):
314-
self.repo.git.symbolic_ref(self.name, write_value[5:])
309+
self.repo.git.symbolic_ref(self.path, write_value[5:])
315310
return
316311
# END non-detached handling
317312

@@ -346,6 +341,10 @@ def from_path(cls, repo, path):
346341
Return
347342
Instance of SymbolicReference or HEAD
348343
depending on the given path
344+
345+
Note
346+
It enforces that symbolic refs in git are only found in the
347+
root of the .git repository, never within a folder.
349348
"""
350349
if not path:
351350
raise ValueError("Cannot create Symbolic Reference from %r" % path)
@@ -366,10 +365,10 @@ class HEAD(SymbolicReference):
366365
_HEAD_NAME = 'HEAD'
367366
__slots__ = tuple()
368367

369-
def __init__(self, repo, name=_HEAD_NAME):
370-
if name != self._HEAD_NAME:
371-
raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, name))
372-
super(HEAD, self).__init__(repo, name)
368+
def __init__(self, repo, path=_HEAD_NAME):
369+
if path != self._HEAD_NAME:
370+
raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, path))
371+
super(HEAD, self).__init__(repo, path)
373372

374373

375374
def reset(self, commit='HEAD', index=True, working_tree = False,

test/git/test_refs.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import git.refs as refs
1111
from git.objects.tag import TagObject
1212
from itertools import chain
13+
import os
1314

1415
class TestRefs(TestBase):
1516

@@ -63,7 +64,7 @@ def test_refs(self):
6364
types_found = set()
6465
for ref in self.rorepo.refs:
6566
types_found.add(type(ref))
66-
assert len(types_found) == 3
67+
assert len(types_found) == 4
6768

6869
@with_rw_repo('0.1.6')
6970
def test_head_reset(self, rw_repo):
@@ -233,7 +234,30 @@ def test_head_reset(self, rw_repo):
233234
self.failUnlessRaises(GitCommandError, far_away_head.checkout)
234235
assert active_branch == active_branch.checkout(force=True)
235236

237+
# test symbolic references which are not at default locations like HEAD
238+
# or FETCH_HEAD - they may also be at spots in refs of course
239+
symbol_ref_path = "refs/symbol_ref"
240+
symref = SymbolicReference(rw_repo, symbol_ref_path)
241+
assert symref.path == symbol_ref_path
242+
symbol_ref_abspath = os.path.join(rw_repo.path, symref.path)
243+
244+
# set it
245+
symref.reference = new_head
246+
assert symref.reference == new_head
247+
assert os.path.isfile(symbol_ref_abspath)
248+
assert symref.commit == new_head.commit
249+
236250
# test ref listing - assure we have packed refs
237-
rw_repo.git.pack_refs(all=True)
238-
assert rw_repo.heads
251+
rw_repo.git.pack_refs(all=True, prune=True)
252+
heads = rw_repo.heads
253+
assert heads
254+
assert new_head in heads
255+
assert active_branch in heads
239256
assert rw_repo.tags
257+
258+
# NOTE: It appears git-cat-file cannot resolve refs which are packed !
259+
# At least it fails here for some reason
260+
# Couldn't reproduce the bug in a simple example though ... lets see.
261+
self.failUnlessRaises(ValueError, getattr, new_head, 'commit')
262+
self.failUnlessRaises(ValueError, getattr, symref, "commit")
263+

0 commit comments

Comments
 (0)