Skip to content

Commit c555840

Browse files
committed
Fetch info can now deal much better with non-default ref specs, fixes #24, #25
1 parent 916c45d commit c555840

File tree

4 files changed

+77
-9
lines changed

4 files changed

+77
-9
lines changed

‎.gitmodules

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
[submodule "gitdb"]
2-
path = git/ext/gitdb
3-
url = git://github.com/gitpython-developers/gitdb.git
1+
[submodule "gitdb"]
2+
path = git/ext/gitdb
3+
url = git://github.com/gitpython-developers/gitdb.git

‎git/ext/gitdb

Submodule gitdb updated 1 file

‎git/remote.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -279,12 +279,36 @@ def _from_line(cls, repo, line, fetch_line):
279279
ref_type = TagReference
280280
else:
281281
raise TypeError("Cannot handle reference type: %r" % ref_type_name)
282+
#END handle ref type
282283

283284
# create ref instance
284285
if ref_type is SymbolicReference:
285286
remote_local_ref = ref_type(repo, "FETCH_HEAD")
286287
else:
287-
remote_local_ref = Reference.from_path(repo, join_path(ref_type._common_path_default, remote_local_ref.strip()))
288+
# determine prefix. Tags are usually pulled into refs/tags, they may have subdirectories.
289+
# It is not clear sometimes where exactly the item is, unless we have an absolute path as indicated
290+
# by the 'ref/' prefix. Otherwise even a tag could be in refs/remotes, which is when it will have the
291+
# 'tags/' subdirectory in its path.
292+
# We don't want to test for actual existence, but try to figure everything out analytically.
293+
ref_path = None
294+
remote_local_ref = remote_local_ref.strip()
295+
if remote_local_ref.startswith(Reference._common_path_default + "/"):
296+
# always use actual type if we get absolute paths
297+
# Will always be the case if something is fetched outside of refs/remotes (if its not a tag)
298+
ref_path = remote_local_ref
299+
if ref_type is not TagReference and not remote_local_ref.startswith(RemoteReference._common_path_default + "/"):
300+
ref_type = Reference
301+
#END downgrade remote reference
302+
elif ref_type is TagReference and 'tags/' in remote_local_ref:
303+
# even though its a tag, it is located in refs/remotes
304+
ref_path = join_path(RemoteReference._common_path_default, remote_local_ref)
305+
else:
306+
ref_path = join_path(ref_type._common_path_default, remote_local_ref)
307+
#END obtain refpath
308+
309+
# even though the path could be within the git conventions, we make
310+
# sure we respect whatever the user wanted, and disabled path checking
311+
remote_local_ref = ref_type(repo, ref_path, check_path=False)
288312
# END create ref instance
289313

290314
note = ( note and note.strip() ) or ''

‎git/test/test_remote.py

+48-4
Original file line numberDiff line numberDiff line change
@@ -443,11 +443,55 @@ def test_creation_and_removal(self, bare_rw_repo):
443443

444444
def test_fetch_info(self):
445445
# assure we can handle remote-tracking branches
446-
fi = FetchInfo._from_line(self.rorepo,
447-
"* [new branch] master -> local/master",
448-
"c437ee5deb8d00cf02f03720693e4c802e99f390 not-for-merge remote-tracking branch '0.3' of git://github.com/gitpython-developers/GitPython")
446+
fetch_info_line_fmt = "c437ee5deb8d00cf02f03720693e4c802e99f390 not-for-merge %s '0.3' of git://github.com/gitpython-developers/GitPython"
447+
remote_info_line_fmt = "* [new branch] nomatter -> %s"
448+
fi = FetchInfo._from_line(self.rorepo,
449+
remote_info_line_fmt % "local/master",
450+
fetch_info_line_fmt % 'remote-tracking branch')
449451
assert fi.ref.is_valid()
450452
assert fi.ref.commit
451453

454+
# handles non-default refspecs: One can specify a different path in refs/remotes
455+
# or a special path just in refs/something for instance
452456

453-
457+
fi = FetchInfo._from_line(self.rorepo,
458+
remote_info_line_fmt % "subdir/tagname",
459+
fetch_info_line_fmt % 'tag')
460+
461+
assert isinstance(fi.ref, TagReference)
462+
assert fi.ref.path.startswith('refs/tags')
463+
464+
# it could be in a remote direcftory though
465+
fi = FetchInfo._from_line(self.rorepo,
466+
remote_info_line_fmt % "remotename/tags/tagname",
467+
fetch_info_line_fmt % 'tag')
468+
469+
assert isinstance(fi.ref, TagReference)
470+
assert fi.ref.path.startswith('refs/remotes/')
471+
472+
# it can also be anywhere !
473+
tag_path = "refs/something/remotename/tags/tagname"
474+
fi = FetchInfo._from_line(self.rorepo,
475+
remote_info_line_fmt % tag_path,
476+
fetch_info_line_fmt % 'tag')
477+
478+
assert isinstance(fi.ref, TagReference)
479+
assert fi.ref.path == tag_path
480+
481+
# branches default to refs/remotes
482+
fi = FetchInfo._from_line(self.rorepo,
483+
remote_info_line_fmt % "remotename/branch",
484+
fetch_info_line_fmt % 'branch')
485+
486+
assert isinstance(fi.ref, RemoteReference)
487+
assert fi.ref.remote_name == 'remotename'
488+
489+
# but you can force it anywhere, in which case we only have a references
490+
fi = FetchInfo._from_line(self.rorepo,
491+
remote_info_line_fmt % "refs/something/branch",
492+
fetch_info_line_fmt % 'branch')
493+
494+
assert type(fi.ref) is Reference
495+
assert fi.ref.path == "refs/something/branch"
496+
497+

0 commit comments

Comments
 (0)