git: adjusted code for new libgit2 backend

- made @CachedProperty use a custom decarator that can do invalidations. This
 is required for tests
- made few cleanups of code since we use a simpler libgit2 backend now
- removed some unused obsolete code
This commit is contained in:
Marcin Kuzminski 2019-07-12 17:39:32 +02:00
parent 94390f644f
commit ccfa86d740
9 changed files with 185 additions and 170 deletions

View file

@ -35,6 +35,7 @@ import urllib
import urlobject
import uuid
import getpass
from functools import update_wrapper, partial
import pygments.lexers
import sqlalchemy
@ -1027,3 +1028,43 @@ def parse_byte_string(size_str):
_parts = match.groups()
num, type_ = _parts
return long(num) * {'mb': 1024*1024, 'kb': 1024}[type_.lower()]
class CachedProperty(object):
"""
Lazy Attributes. With option to invalidate the cache by running a method
class Foo():
@CachedProperty
def heavy_func():
return 'super-calculation'
foo = Foo()
foo.heavy_func() # first computions
foo.heavy_func() # fetch from cache
foo._invalidate_prop_cache('heavy_func')
# at this point calling foo.heavy_func() will be re-computed
"""
def __init__(self, func, func_name=None):
if func_name is None:
func_name = func.__name__
self.data = (func, func_name)
update_wrapper(self, func)
def __get__(self, inst, class_):
if inst is None:
return self
func, func_name = self.data
value = func(inst)
inst.__dict__[func_name] = value
if '_invalidate_prop_cache' not in inst.__dict__:
inst.__dict__['_invalidate_prop_cache'] = partial(
self._invalidate_prop_cache, inst)
return value
def _invalidate_prop_cache(self, inst, name):
inst.__dict__.pop(name, None)

View file

@ -33,12 +33,12 @@ import collections
import warnings
from zope.cachedescriptors.property import Lazy as LazyProperty
from zope.cachedescriptors.property import CachedProperty
from pyramid import compat
import rhodecode
from rhodecode.translation import lazy_ugettext
from rhodecode.lib.utils2 import safe_str, safe_unicode
from rhodecode.lib.utils2 import safe_str, safe_unicode, CachedProperty
from rhodecode.lib.vcs import connection
from rhodecode.lib.vcs.utils import author_name, author_email
from rhodecode.lib.vcs.conf import settings
@ -264,7 +264,9 @@ class BaseRepository(object):
EMPTY_COMMIT_ID = '0' * 40
path = None
_commit_ids_ver = 0
_is_empty = None
_commit_ids = {}
def __init__(self, repo_path, config=None, create=False, **kwargs):
"""
@ -386,8 +388,23 @@ class BaseRepository(object):
commit = self.get_commit(commit_id)
return commit.size
def _check_for_empty(self):
no_commits = len(self._commit_ids) == 0
if no_commits:
# check on remote to be sure
return self._remote.is_empty()
else:
return False
def is_empty(self):
return self._remote.is_empty()
if rhodecode.is_test:
return self._check_for_empty()
if self._is_empty is None:
# cache empty for production, but not tests
self._is_empty = self._check_for_empty()
return self._is_empty
@staticmethod
def check_url(url, config):
@ -408,14 +425,15 @@ class BaseRepository(object):
# COMMITS
# ==========================================================================
@CachedProperty('_commit_ids_ver')
@CachedProperty
def commit_ids(self):
raise NotImplementedError
def append_commit_id(self, commit_id):
if commit_id not in self.commit_ids:
self._rebuild_cache(self.commit_ids + [commit_id])
self._commit_ids_ver = time.time()
# clear cache
self._invalidate_prop_cache('commit_ids')
def get_commit(self, commit_id=None, commit_idx=None, pre_load=None, translate_tag=None):
"""

View file

@ -46,12 +46,6 @@ class GitCommit(base.BaseCommit):
"""
Represents state of the repository at single commit id.
"""
_author_property = 'author'
_committer_property = 'committer'
_date_property = 'commit_time'
_date_tz_property = 'commit_timezone'
_message_property = 'message'
_parents_property = 'parents'
_filter_pre_load = [
# done through a more complex tree walk on parents
@ -124,23 +118,19 @@ class GitCommit(base.BaseCommit):
@LazyProperty
def message(self):
return safe_unicode(
self._remote.commit_attribute(self.id, self._message_property))
return safe_unicode(self._remote.message(self.id))
@LazyProperty
def committer(self):
return safe_unicode(
self._remote.commit_attribute(self.id, self._committer_property))
return safe_unicode(self._remote.author(self.id))
@LazyProperty
def author(self):
return safe_unicode(
self._remote.commit_attribute(self.id, self._author_property))
return safe_unicode(self._remote.author(self.id))
@LazyProperty
def date(self):
unix_ts, tz = self._remote.get_object_attrs(
self.raw_id, self._date_property, self._date_tz_property)
unix_ts, tz = self._remote.date(self.raw_id)
return utcdate_fromtimestamp(unix_ts, tz)
@LazyProperty
@ -158,13 +148,23 @@ class GitCommit(base.BaseCommit):
return tags
@LazyProperty
def branch(self):
def commit_branches(self):
branches = []
for name, commit_id in self.repository.branches.iteritems():
if commit_id == self.raw_id:
return safe_unicode(name)
branches.append(name)
return branches
@LazyProperty
def branch(self):
# actually commit can have multiple branches
branches = self.commit_branches
if branches:
return branches[0]
return None
def _get_id_for_path(self, path):
def _get_tree_id_for_path(self, path):
path = safe_str(path)
if path in self._paths:
return self._paths[path]
@ -177,56 +177,26 @@ class GitCommit(base.BaseCommit):
self._paths[''] = data
return data
parts = path.split('/')
dirs, name = parts[:-1], parts[-1]
cur_dir = ''
tree_id, tree_type, tree_mode = \
self._remote.tree_and_type_for_path(self.raw_id, path)
if tree_id is None:
raise self.no_node_at_path(path)
# initially extract things from root dir
tree_items = self._remote.tree_items(tree_id)
self._process_tree_items(tree_items, cur_dir)
for dir in dirs:
if cur_dir:
cur_dir = '/'.join((cur_dir, dir))
else:
cur_dir = dir
dir_id = None
for item, stat_, id_, type_ in tree_items:
if item == dir:
dir_id = id_
break
if dir_id:
if type_ != "tree":
raise CommitError('%s is not a directory' % cur_dir)
# update tree
tree_items = self._remote.tree_items(dir_id)
else:
raise CommitError('%s have not been found' % cur_dir)
# cache all items from the given traversed tree
self._process_tree_items(tree_items, cur_dir)
self._paths[path] = [tree_id, tree_type]
self._stat_modes[path] = tree_mode
if path not in self._paths:
raise self.no_node_at_path(path)
return self._paths[path]
def _process_tree_items(self, items, cur_dir):
for item, stat_, id_, type_ in items:
if cur_dir:
name = '/'.join((cur_dir, item))
else:
name = item
self._paths[name] = [id_, type_]
self._stat_modes[name] = stat_
def _get_kind(self, path):
path_id, type_ = self._get_id_for_path(path)
tree_id, type_ = self._get_tree_id_for_path(path)
if type_ == 'blob':
return NodeKind.FILE
elif type_ == 'tree':
return NodeKind.DIR
elif type == 'link':
elif type_ == 'link':
return NodeKind.SUBMODULE
return None
@ -245,8 +215,7 @@ class GitCommit(base.BaseCommit):
"""
Returns list of parent commits.
"""
parent_ids = self._remote.commit_attribute(
self.id, self._parents_property)
parent_ids = self._remote.parents(self.id)
return self._make_commits(parent_ids)
@LazyProperty
@ -266,11 +235,11 @@ class GitCommit(base.BaseCommit):
child_ids.extend(found_ids)
return self._make_commits(child_ids)
def _make_commits(self, commit_ids, pre_load=None):
return [
self.repository.get_commit(commit_id=commit_id, pre_load=pre_load,
translate_tag=False)
for commit_id in commit_ids]
def _make_commits(self, commit_ids):
def commit_maker(_commit_id):
return self.repository.get_commit(commit_id=commit_id)
return [commit_maker(commit_id) for commit_id in commit_ids]
def get_file_mode(self, path):
"""
@ -278,7 +247,7 @@ class GitCommit(base.BaseCommit):
"""
path = safe_str(path)
# ensure path is traversed
self._get_id_for_path(path)
self._get_tree_id_for_path(path)
return self._stat_modes[path]
def is_link(self, path):
@ -288,15 +257,15 @@ class GitCommit(base.BaseCommit):
"""
Returns content of the file at given `path`.
"""
id_, _ = self._get_id_for_path(path)
return self._remote.blob_as_pretty_string(id_)
tree_id, _ = self._get_tree_id_for_path(path)
return self._remote.blob_as_pretty_string(tree_id)
def get_file_size(self, path):
"""
Returns size of the file at given `path`.
"""
id_, _ = self._get_id_for_path(path)
return self._remote.blob_raw_length(id_)
tree_id, _ = self._get_tree_id_for_path(path)
return self._remote.blob_raw_length(tree_id)
def get_path_history(self, path, limit=None, pre_load=None):
"""
@ -350,20 +319,23 @@ class GitCommit(base.BaseCommit):
line)
def get_nodes(self, path):
if self._get_kind(path) != NodeKind.DIR:
raise CommitError(
"Directory does not exist for commit %s at '%s'" % (self.raw_id, path))
path = self._fix_path(path)
id_, _ = self._get_id_for_path(path)
tree_id = self._remote[id_]['id']
tree_id, _ = self._get_tree_id_for_path(path)
dirnodes = []
filenodes = []
alias = self.repository.alias
# extracted tree ID gives us our files...
for name, stat_, id_, type_ in self._remote.tree_items(tree_id):
if type_ == 'link':
url = self._get_submodule_url('/'.join((path, name)))
dirnodes.append(SubModuleNode(
name, url=url, commit=id_, alias=alias))
name, url=url, commit=id_, alias=self.repository.alias))
continue
if path != '':
@ -394,7 +366,7 @@ class GitCommit(base.BaseCommit):
path = self._fix_path(path)
if path not in self.nodes:
try:
id_, type_ = self._get_id_for_path(path)
tree_id, type_ = self._get_tree_id_for_path(path)
except CommitError:
raise NodeDoesNotExistError(
"Cannot find one of parents' directories for a given "
@ -402,7 +374,7 @@ class GitCommit(base.BaseCommit):
if type_ == 'link':
url = self._get_submodule_url(path)
node = SubModuleNode(path, url=url, commit=id_,
node = SubModuleNode(path, url=url, commit=tree_id,
alias=self.repository.alias)
elif type_ == 'tree':
if path == '':
@ -411,16 +383,18 @@ class GitCommit(base.BaseCommit):
node = DirNode(path, commit=self)
elif type_ == 'blob':
node = FileNode(path, commit=self, pre_load=pre_load)
self._stat_modes[path] = node.mode
else:
raise self.no_node_at_path(path)
# cache node
self.nodes[path] = node
return self.nodes[path]
def get_largefile_node(self, path):
id_, _ = self._get_id_for_path(path)
pointer_spec = self._remote.is_large_file(id_)
tree_id, _ = self._get_tree_id_for_path(path)
pointer_spec = self._remote.is_large_file(tree_id)
if pointer_spec:
# content of that file regular FileNode is the hash of largefile

View file

@ -25,15 +25,14 @@ GIT repository module
import logging
import os
import re
import time
from zope.cachedescriptors.property import Lazy as LazyProperty
from zope.cachedescriptors.property import CachedProperty
from rhodecode.lib.compat import OrderedDict
from rhodecode.lib.datelib import (
utcdate_fromtimestamp, makedate, date_astimestamp)
from rhodecode.lib.utils import safe_unicode, safe_str
from rhodecode.lib.utils2 import CachedProperty
from rhodecode.lib.vcs import connection, path as vcspath
from rhodecode.lib.vcs.backends.base import (
BaseRepository, CollectionGenerator, Config, MergeResponse,
@ -71,9 +70,6 @@ class GitRepository(BaseRepository):
# caches
self._commit_ids = {}
# dependent that trigger re-computation of commit_ids
self._commit_ids_ver = 0
@LazyProperty
def _remote(self):
return connection.Git(self.path, self.config, with_wire=self.with_wire)
@ -86,7 +82,7 @@ class GitRepository(BaseRepository):
def head(self):
return self._remote.head()
@CachedProperty('_commit_ids_ver')
@CachedProperty
def commit_ids(self):
"""
Returns list of commit ids, in ascending order. Being lazy
@ -190,12 +186,16 @@ class GitRepository(BaseRepository):
except OSError as err:
raise RepositoryError(err)
def _get_all_commit_ids(self, filters=None):
def _get_all_commit_ids(self):
return self._remote.get_all_commit_ids()
def _get_commit_ids(self, filters=None):
# we must check if this repo is not empty, since later command
# fails if it is. And it's cheaper to ask than throw the subprocess
# errors
head = self._remote.head(show_exc=False)
if not head:
return []
@ -208,7 +208,7 @@ class GitRepository(BaseRepository):
if filters.get('until'):
extra_filter.append('--until=%s' % (filters['until']))
if filters.get('branch_name'):
rev_filter = ['--tags']
rev_filter = []
extra_filter.append(filters['branch_name'])
rev_filter.extend(extra_filter)
@ -233,6 +233,8 @@ class GitRepository(BaseRepository):
if commit_id_or_idx in (None, '', 'tip', 'HEAD', 'head', -1):
return self.commit_ids[-1]
commit_missing_err = "Commit {} does not exist for `{}`".format(
*map(safe_str, [commit_id_or_idx, self.name]))
is_bstr = isinstance(commit_id_or_idx, (str, unicode))
if ((is_bstr and commit_id_or_idx.isdigit() and len(commit_id_or_idx) < 12)
@ -240,30 +242,15 @@ class GitRepository(BaseRepository):
try:
commit_id_or_idx = self.commit_ids[int(commit_id_or_idx)]
except Exception:
msg = "Commit {} does not exist for `{}`".format(commit_id_or_idx, self.name)
raise CommitDoesNotExistError(msg)
raise CommitDoesNotExistError(commit_missing_err)
elif is_bstr:
# check full path ref, eg. refs/heads/master
ref_id = self._refs.get(commit_id_or_idx)
if ref_id:
return ref_id
# check branch name
branch_ids = self.branches.values()
ref_id = self._refs.get('refs/heads/%s' % commit_id_or_idx)
if ref_id:
return ref_id
# check tag name
ref_id = self._refs.get('refs/tags/%s' % commit_id_or_idx)
if ref_id:
return ref_id
if (not SHA_PATTERN.match(commit_id_or_idx) or
commit_id_or_idx not in self.commit_ids):
msg = "Commit {} does not exist for `{}`".format(commit_id_or_idx, self.name)
raise CommitDoesNotExistError(msg)
# Need to call remote to translate id for tagging scenario
try:
remote_data = self._remote.get_object(commit_id_or_idx)
commit_id_or_idx = remote_data["commit_id"]
except (CommitDoesNotExistError,):
raise CommitDoesNotExistError(commit_missing_err)
# Ensure we return full id
if not SHA_PATTERN.match(str(commit_id_or_idx)):
@ -327,32 +314,31 @@ class GitRepository(BaseRepository):
def _get_branches(self):
return self._get_refs_entries(prefix='refs/heads/', strip_prefix=True)
@LazyProperty
@CachedProperty
def branches(self):
return self._get_branches()
@LazyProperty
@CachedProperty
def branches_closed(self):
return {}
@LazyProperty
@CachedProperty
def bookmarks(self):
return {}
@LazyProperty
@CachedProperty
def branches_all(self):
all_branches = {}
all_branches.update(self.branches)
all_branches.update(self.branches_closed)
return all_branches
@LazyProperty
@CachedProperty
def tags(self):
return self._get_tags()
def _get_tags(self):
return self._get_refs_entries(
prefix='refs/tags/', strip_prefix=True, reverse=True)
return self._get_refs_entries(prefix='refs/tags/', strip_prefix=True, reverse=True)
def tag(self, name, user, commit_id=None, message=None, date=None,
**kwargs):
@ -368,15 +354,17 @@ class GitRepository(BaseRepository):
:raises TagAlreadyExistError: if tag with same name already exists
"""
print self._refs
if name in self.tags:
raise TagAlreadyExistError("Tag %s already exists" % name)
commit = self.get_commit(commit_id=commit_id)
message = message or "Added tag %s for commit %s" % (
name, commit.raw_id)
self._remote.set_refs('refs/tags/%s' % name, commit._commit['id'])
message = message or "Added tag %s for commit %s" % (name, commit.raw_id)
self._remote.set_refs('refs/tags/%s' % name, commit.raw_id)
self._invalidate_prop_cache('tags')
self._invalidate_prop_cache('_refs')
self._refs = self._get_refs()
self.tags = self._get_tags()
return commit
def remove_tag(self, name, user, message=None, date=None):
@ -392,19 +380,15 @@ class GitRepository(BaseRepository):
"""
if name not in self.tags:
raise TagDoesNotExistError("Tag %s does not exist" % name)
tagpath = vcspath.join(
self._remote.get_refs_path(), 'refs', 'tags', name)
try:
os.remove(tagpath)
self._refs = self._get_refs()
self.tags = self._get_tags()
except OSError as e:
raise RepositoryError(e.strerror)
self._remote.tag_remove(name)
self._invalidate_prop_cache('tags')
self._invalidate_prop_cache('_refs')
def _get_refs(self):
return self._remote.get_refs()
@LazyProperty
@CachedProperty
def _refs(self):
return self._get_refs()
@ -455,18 +439,13 @@ class GitRepository(BaseRepository):
else:
commit_id = "tip"
commit_id = self._lookup_commit(commit_id)
remote_idx = None
if translate_tag:
# Need to call remote to translate id for tagging scenario
remote_data = self._remote.get_object(commit_id)
commit_id = remote_data["commit_id"]
remote_idx = remote_data["idx"]
commit_id = self._lookup_commit(commit_id)
try:
idx = self._commit_ids[commit_id]
except KeyError:
idx = remote_idx or 0
idx = -1
return GitCommit(self, commit_id, idx, pre_load=pre_load)
@ -539,14 +518,8 @@ class GitRepository(BaseRepository):
'start': start_pos,
'end': end_pos,
}
commit_ids = self._get_all_commit_ids(filters=revfilters)
commit_ids = self._get_commit_ids(filters=revfilters)
# pure python stuff, it's slow due to walker walking whole repo
# def get_revs(walker):
# for walker_entry in walker:
# yield walker_entry.commit.id
# revfilters = {}
# commit_ids = list(reversed(list(get_revs(self._repo.get_walker(**revfilters)))))
else:
commit_ids = self.commit_ids
@ -613,8 +586,11 @@ class GitRepository(BaseRepository):
commit = commit.parents[0]
self._remote.set_refs('refs/heads/%s' % branch_name, commit.raw_id)
self._commit_ids_ver = time.time()
# we updated _commit_ids_ver so accessing self.commit_ids will re-compute it
# clear cached properties
self._invalidate_prop_cache('commit_ids')
self._invalidate_prop_cache('_refs')
self._invalidate_prop_cache('branches')
return len(self.commit_ids)
def get_common_ancestor(self, commit_id1, commit_id2, repo2):
@ -697,9 +673,11 @@ class GitRepository(BaseRepository):
def set_refs(self, ref_name, commit_id):
self._remote.set_refs(ref_name, commit_id)
self._invalidate_prop_cache('_refs')
def remove_ref(self, ref_name):
self._remote.remove_ref(ref_name)
self._invalidate_prop_cache('_refs')
def _update_server_info(self):
"""
@ -744,6 +722,12 @@ class GitRepository(BaseRepository):
cmd.append(branch_name)
self.run_git_command(cmd, fail_on_stderr=False)
def _create_branch(self, branch_name, commit_id):
"""
creates a branch in a GIT repo
"""
self._remote.create_branch(branch_name, commit_id)
def _identify(self):
"""
Return the current state of the working directory.

View file

@ -299,10 +299,11 @@ class MercurialCommit(base.BaseCommit):
loc = vals[0]
commit = vals[1]
dirnodes.append(SubModuleNode(k, url=loc, commit=commit, alias=alias))
nodes = dirnodes + filenodes
# cache nodes
for node in nodes:
self.nodes[node.path] = node
if node.path not in self.nodes:
self.nodes[node.path] = node
nodes.sort()
return nodes

View file

@ -24,16 +24,15 @@ HG repository module
import os
import logging
import binascii
import time
import urllib
from zope.cachedescriptors.property import Lazy as LazyProperty
from zope.cachedescriptors.property import CachedProperty
from rhodecode.lib.compat import OrderedDict
from rhodecode.lib.datelib import (
date_to_timestamp_plus_offset, utcdate_fromtimestamp, makedate)
from rhodecode.lib.utils import safe_unicode, safe_str
from rhodecode.lib.utils2 import CachedProperty
from rhodecode.lib.vcs import connection, exceptions
from rhodecode.lib.vcs.backends.base import (
BaseRepository, CollectionGenerator, Config, MergeResponse,
@ -87,14 +86,11 @@ class MercurialRepository(BaseRepository):
# caches
self._commit_ids = {}
# dependent that trigger re-computation of commit_ids
self._commit_ids_ver = 0
@LazyProperty
def _remote(self):
return connection.Hg(self.path, self.config, with_wire=self.with_wire)
@CachedProperty('_commit_ids_ver')
@CachedProperty
def commit_ids(self):
"""
Returns list of commit ids, in ascending order. Being lazy
@ -108,15 +104,15 @@ class MercurialRepository(BaseRepository):
self._commit_ids = dict((commit_id, index)
for index, commit_id in enumerate(commit_ids))
@LazyProperty
@CachedProperty
def branches(self):
return self._get_branches()
@LazyProperty
@CachedProperty
def branches_closed(self):
return self._get_branches(active=False, closed=True)
@LazyProperty
@CachedProperty
def branches_all(self):
all_branches = {}
all_branches.update(self.branches)
@ -143,7 +139,7 @@ class MercurialRepository(BaseRepository):
return OrderedDict(sorted(_branches, key=get_name, reverse=False))
@LazyProperty
@CachedProperty
def tags(self):
"""
Gets tags for this repository
@ -276,8 +272,9 @@ class MercurialRepository(BaseRepository):
self._remote.strip(commit_id, update=False, backup="none")
self._remote.invalidate_vcs_cache()
self._commit_ids_ver = time.time()
# we updated _commit_ids_ver so accessing self.commit_ids will re-compute it
# clear cache
self._invalidate_prop_cache('commit_ids')
return len(self.commit_ids)
def verify(self):

View file

@ -27,11 +27,11 @@ import os
import urllib
from zope.cachedescriptors.property import Lazy as LazyProperty
from zope.cachedescriptors.property import CachedProperty
from rhodecode.lib.compat import OrderedDict
from rhodecode.lib.datelib import date_astimestamp
from rhodecode.lib.utils import safe_str, safe_unicode
from rhodecode.lib.utils2 import CachedProperty
from rhodecode.lib.vcs import connection, path as vcspath
from rhodecode.lib.vcs.backends import base
from rhodecode.lib.vcs.backends.svn.commit import (
@ -76,8 +76,9 @@ class SubversionRepository(base.BaseRepository):
self._init_repo(create, src_url)
# dependent that trigger re-computation of commit_ids
self._commit_ids_ver = 0
# caches
self._commit_ids = {}
@LazyProperty
def _remote(self):
@ -97,7 +98,7 @@ class SubversionRepository(base.BaseRepository):
else:
self._check_path()
@CachedProperty('_commit_ids_ver')
@CachedProperty
def commit_ids(self):
head = self._remote.lookup(None)
return [str(r) for r in xrange(1, head + 1)]

View file

@ -46,6 +46,7 @@ class TestGitRepository(object):
@pytest.fixture(autouse=True)
def prepare(self, request, baseapp):
self.repo = GitRepository(TEST_GIT_REPO, bare=True)
self.repo.count()
def get_clone_repo(self, tmp_path_factory):
"""
@ -1242,7 +1243,7 @@ class TestGetSubmoduleUrl(object):
commit = GitCommit(repository=repository, raw_id='abcdef12', idx=1)
submodule_url = 'https://code.rhodecode.com/dulwich'
get_id_patch = mock.patch.object(
commit, '_get_id_for_path', return_value=(1, 'link'))
commit, '_get_tree_id_for_path', return_value=(1, 'link'))
get_submodule_patch = mock.patch.object(
commit, '_get_submodule_url', return_value=submodule_url)
@ -1262,7 +1263,7 @@ class TestGetSubmoduleUrl(object):
commit = GitCommit(repository=repository, raw_id='abcdef12', idx=1)
submodule_url = 'https://code.rhodecode.com/dulwich'
get_id_patch = mock.patch.object(
commit, '_get_id_for_path', return_value=(1, 'tree'))
commit, '_get_tree_id_for_path', return_value=(1, 'tree'))
get_submodule_patch = mock.patch.object(
commit, '_get_submodule_url', return_value=submodule_url)

View file

@ -88,8 +88,6 @@ class TestInMemoryCommit(BackendTestMixin):
@pytest.mark.backends("git")
def test_add_on_branch_git(self, nodes):
self.repo._checkout('stable', create=True)
for node in nodes:
self.imc.add(node)
self.commit(branch=u'stable')