I'm working with dulwich on a project where I need to clone repositories sometimes by commit ID, sometimes by tag, sometimes by branch name. I'm having trouble with the tag case which seems to work for some repositories, but not for others.
Here's the "clone
" helper function I wrote:
from dulwich import index
from dulwich.client import get_transport_and_path
from dulwich.repo import Repo
def clone(repo_url, ref, folder):
is_commit = False
if not ref.startswith('refs/'):
is_commit = True
rep = Repo.init(folder)
client, relative_path = get_transport_and_path(repo_url)
remote_refs = client.fetch(relative_path, rep)
for k, v in remote_refs.iteritems():
try:
rep.refs.add_if_new(k, v)
except:
pass
if ref.startswith('refs/tags'):
ref = rep.ref(ref)
is_commit = True
if is_commit:
rep['HEAD'] = rep.commit(ref)
else:
rep['HEAD'] = remote_refs[ref]
indexfile = rep.index_path()
tree = rep["HEAD"].tree
index.build_index_from_tree(rep.path, indexfile, rep.object_store, tree)
return rep, folder
Oddly, I am able to do
clone('git://github.com/dotcloud/docker-py', 'refs/tags/0.2.0', '/tmp/a')
But
clone('git://github.com/dotcloud/docker-registry', 'refs/tags/0.6.0', '/tmp/b')
fails with
NotCommitError: object debd567e95df51f8ac91d0bb69ca35037d957ee6
type commit
[...]
is not a commit
Both refs are tags, so I'm not sure what I'm doing wrong, or why the code behaves differently on both repositories. Would appreciate any help to sort this out!
refs/tags/0.6.0 is an annotated tag. This means that the ref for it points to a Tag object (which then has a reference to a commit object), rather than directly to a Commit object.
In this line:
if is_commit:
rep['HEAD'] = rep.commit(ref)
else:
rep['HEAD'] = remote_refs[ref]
you probably just want to do something like:
if isinstance(rep[ref], Tag):
rep['HEAD'] = rep[ref].object[1]
else:
rep['HEAD'] = rep[ref]