diff --git a/rhodecode/api/views/pull_request_api.py b/rhodecode/api/views/pull_request_api.py
--- a/rhodecode/api/views/pull_request_api.py
+++ b/rhodecode/api/views/pull_request_api.py
@@ -302,7 +302,7 @@ def merge_pull_request(
         request.environ, repo_name=target_repo.repo_name,
         username=apiuser.username, action='push',
         scm=target_repo.repo_type)
-    merge_response = PullRequestModel().merge(
+    merge_response = PullRequestModel().merge_repo(
         pull_request, apiuser, extras=extras)
     if merge_response.executed:
         PullRequestModel().close_pull_request(
diff --git a/rhodecode/apps/repository/tests/test_repo_pullrequests.py b/rhodecode/apps/repository/tests/test_repo_pullrequests.py
--- a/rhodecode/apps/repository/tests/test_repo_pullrequests.py
+++ b/rhodecode/apps/repository/tests/test_repo_pullrequests.py
@@ -618,7 +618,7 @@ class TestPullrequestsView(object):
 
         model_patcher = mock.patch.multiple(
             PullRequestModel,
-            merge=mock.Mock(return_value=MergeResponse(
+            merge_repo=mock.Mock(return_value=MergeResponse(
                 True, False, 'STUB_COMMIT_ID', MergeFailureReason.PUSH_FAILED)),
             merge_status=mock.Mock(return_value=(True, 'WRONG_MESSAGE')))
 
diff --git a/rhodecode/apps/repository/views/repo_pull_requests.py b/rhodecode/apps/repository/views/repo_pull_requests.py
--- a/rhodecode/apps/repository/views/repo_pull_requests.py
+++ b/rhodecode/apps/repository/views/repo_pull_requests.py
@@ -340,7 +340,8 @@ class RepoPullRequestsView(RepoAppView, 
         # check merge capabilities
         _merge_check = MergeCheck.validate(
             pull_request_latest, user=self._rhodecode_user,
-            translator=self.request.translate, force_shadow_repo_refresh=force_refresh)
+            translator=self.request.translate,
+            force_shadow_repo_refresh=force_refresh)
         c.pr_merge_errors = _merge_check.error_details
         c.pr_merge_possible = not _merge_check.failed
         c.pr_merge_message = _merge_check.merge_msg
@@ -1063,7 +1064,7 @@ class RepoPullRequestsView(RepoAppView, 
 
     def _merge_pull_request(self, pull_request, user, extras):
         _ = self.request.translate
-        merge_resp = PullRequestModel().merge(pull_request, user, extras=extras)
+        merge_resp = PullRequestModel().merge_repo(pull_request, user, extras=extras)
 
         if merge_resp.executed:
             log.debug("The merge was successful, closing the pull request.")
diff --git a/rhodecode/lib/middleware/simplevcs.py b/rhodecode/lib/middleware/simplevcs.py
--- a/rhodecode/lib/middleware/simplevcs.py
+++ b/rhodecode/lib/middleware/simplevcs.py
@@ -204,13 +204,14 @@ class SimpleVCS(object):
 
             # Only proceed if we got a pull request and if acl repo name from
             # URL equals the target repo name of the pull request.
-            if pull_request and (acl_repo_name ==
-                                 pull_request.target_repo.repo_name):
+            if pull_request and \
+                    (acl_repo_name == pull_request.target_repo.repo_name):
+                repo_id = pull_request.target_repo.repo_id
                 # Get file system path to shadow repository.
                 workspace_id = PullRequestModel()._workspace_id(pull_request)
                 target_vcs = pull_request.target_repo.scm_instance()
                 vcs_repo_name = target_vcs._get_shadow_repository_path(
-                    workspace_id)
+                    repo_id, workspace_id)
 
                 # Store names for later usage.
                 self.vcs_repo_name = vcs_repo_name
diff --git a/rhodecode/lib/vcs/backends/base.py b/rhodecode/lib/vcs/backends/base.py
--- a/rhodecode/lib/vcs/backends/base.py
+++ b/rhodecode/lib/vcs/backends/base.py
@@ -451,7 +451,7 @@ class BaseRepository(object):
         """
         raise NotImplementedError
 
-    def merge(self, target_ref, source_repo, source_ref, workspace_id,
+    def merge(self, repo_id, workspace_id, target_ref, source_repo, source_ref,
               user_name='', user_email='', message='', dry_run=False,
               use_rebase=False, close_branch=False):
         """
@@ -465,13 +465,14 @@ class BaseRepository(object):
         'possible', 'executed', 'source_commit', 'target_commit',
         'merge_commit'.
 
+        :param repo_id: `repo_id` target repo id.
+        :param workspace_id: `workspace_id` unique identifier.
         :param target_ref: `target_ref` points to the commit on top of which
             the `source_ref` should be merged.
         :param source_repo: The repository that contains the commits to be
             merged.
         :param source_ref: `source_ref` points to the topmost commit from
             the `source_repo` which should be merged.
-        :param workspace_id: `workspace_id` unique identifier.
         :param user_name: Merge commit `user_name`.
         :param user_email: Merge commit `user_email`.
         :param message: Merge commit `message`.
@@ -492,12 +493,9 @@ class BaseRepository(object):
             if not message:
                 raise ValueError('message cannot be empty')
 
-        shadow_repository_path = self._maybe_prepare_merge_workspace(
-            workspace_id, target_ref, source_ref)
-
         try:
             return self._merge_repo(
-                shadow_repository_path, target_ref, source_repo,
+                repo_id, workspace_id, target_ref, source_repo,
                 source_ref, message, user_name, user_email, dry_run=dry_run,
                 use_rebase=use_rebase, close_branch=close_branch)
         except RepositoryError:
@@ -507,14 +505,15 @@ class BaseRepository(object):
             return MergeResponse(
                 False, False, None, MergeFailureReason.UNKNOWN)
 
-    def _merge_repo(self, shadow_repository_path, target_ref,
+    def _merge_repo(self, repo_id, workspace_id, target_ref,
                     source_repo, source_ref, merge_message,
                     merger_name, merger_email, dry_run=False,
                     use_rebase=False, close_branch=False):
         """Internal implementation of merge."""
         raise NotImplementedError
 
-    def _maybe_prepare_merge_workspace(self, workspace_id, target_ref, source_ref):
+    def _maybe_prepare_merge_workspace(
+            self, repo_id, workspace_id, target_ref, source_ref):
         """
         Create the merge workspace.
 
@@ -522,10 +521,27 @@ class BaseRepository(object):
         """
         raise NotImplementedError
 
-    def _get_shadow_repository_path(self, workspace_id):
-        raise NotImplementedError
+    def _get_legacy_shadow_repository_path(self, workspace_id):
+        """
+        Legacy version that was used before. We still need it for
+        backward compat
+        """
+        return os.path.join(
+            os.path.dirname(self.path),
+            '.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id))
 
-    def cleanup_merge_workspace(self, workspace_id):
+    def _get_shadow_repository_path(self, repo_id, workspace_id):
+        # The name of the shadow repository must start with '.', so it is
+        # skipped by 'rhodecode.lib.utils.get_filesystem_repos'.
+        legacy_repository_path = self._get_legacy_shadow_repository_path(workspace_id)
+        if os.path.exists(legacy_repository_path):
+            return legacy_repository_path
+        else:
+            return os.path.join(
+                os.path.dirname(self.path),
+                '.__shadow_repo_%s_%s' % (repo_id, workspace_id))
+
+    def cleanup_merge_workspace(self, repo_id, workspace_id):
         """
         Remove merge workspace.
 
@@ -534,7 +550,7 @@ class BaseRepository(object):
 
         :param workspace_id: `workspace_id` unique identifier.
         """
-        shadow_repository_path = self._get_shadow_repository_path(workspace_id)
+        shadow_repository_path = self._get_shadow_repository_path(repo_id, workspace_id)
         shadow_repository_path_del = '{}.{}.delete'.format(
             shadow_repository_path, time.time())
 
diff --git a/rhodecode/lib/vcs/backends/git/repository.py b/rhodecode/lib/vcs/backends/git/repository.py
--- a/rhodecode/lib/vcs/backends/git/repository.py
+++ b/rhodecode/lib/vcs/backends/git/repository.py
@@ -902,7 +902,19 @@ class GitRepository(BaseRepository):
 
         return '%s%d' % (prefix, branch_id)
 
-    def _merge_repo(self, shadow_repository_path, target_ref,
+    def _maybe_prepare_merge_workspace(
+            self, repo_id, workspace_id, target_ref, source_ref):
+        shadow_repository_path = self._get_shadow_repository_path(
+            repo_id, workspace_id)
+        if not os.path.exists(shadow_repository_path):
+            self._local_clone(
+                shadow_repository_path, target_ref.name, source_ref.name)
+            log.debug(
+                'Prepared shadow repository in %s', shadow_repository_path)
+
+        return shadow_repository_path
+
+    def _merge_repo(self, repo_id, workspace_id, target_ref,
                     source_repo, source_ref, merge_message,
                     merger_name, merger_email, dry_run=False,
                     use_rebase=False, close_branch=False):
@@ -912,7 +924,10 @@ class GitRepository(BaseRepository):
             return MergeResponse(
                 False, False, None, MergeFailureReason.TARGET_IS_NOT_HEAD)
 
-        shadow_repo = GitRepository(shadow_repository_path)
+        shadow_repository_path = self._maybe_prepare_merge_workspace(
+            repo_id, workspace_id, target_ref, source_ref)
+        shadow_repo = self._get_shadow_instance(shadow_repository_path)
+
         # checkout source, if it's different. Otherwise we could not
         # fetch proper commits for merge testing
         if source_ref.name != target_ref.name:
@@ -929,7 +944,7 @@ class GitRepository(BaseRepository):
 
         # Need to reload repo to invalidate the cache, or otherwise we cannot
         # retrieve the last target commit.
-        shadow_repo = GitRepository(shadow_repository_path)
+        shadow_repo = self._get_shadow_instance(shadow_repository_path)
         if target_ref.commit_id != shadow_repo.branches[target_ref.name]:
             log.warning('Shadow Target ref %s commit mismatch %s vs %s',
                         target_ref, target_ref.commit_id,
@@ -989,18 +1004,3 @@ class GitRepository(BaseRepository):
         return MergeResponse(
             merge_possible, merge_succeeded, merge_ref,
             merge_failure_reason)
-
-    def _get_shadow_repository_path(self, workspace_id):
-        # The name of the shadow repository must start with '.', so it is
-        # skipped by 'rhodecode.lib.utils.get_filesystem_repos'.
-        return os.path.join(
-            os.path.dirname(self.path),
-            '.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id))
-
-    def _maybe_prepare_merge_workspace(self, workspace_id, target_ref, source_ref):
-        shadow_repository_path = self._get_shadow_repository_path(workspace_id)
-        if not os.path.exists(shadow_repository_path):
-            self._local_clone(
-                shadow_repository_path, target_ref.name, source_ref.name)
-
-        return shadow_repository_path
diff --git a/rhodecode/lib/vcs/backends/hg/repository.py b/rhodecode/lib/vcs/backends/hg/repository.py
--- a/rhodecode/lib/vcs/backends/hg/repository.py
+++ b/rhodecode/lib/vcs/backends/hg/repository.py
@@ -681,15 +681,10 @@ class MercurialRepository(BaseRepository
             return ref.name
         return self._remote.ctx_branch(ref.commit_id)
 
-    def _get_shadow_repository_path(self, workspace_id):
-        # The name of the shadow repository must start with '.', so it is
-        # skipped by 'rhodecode.lib.utils.get_filesystem_repos'.
-        return os.path.join(
-            os.path.dirname(self.path),
-            '.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id))
-
-    def _maybe_prepare_merge_workspace(self, workspace_id, unused_target_ref, unused_source_ref):
-        shadow_repository_path = self._get_shadow_repository_path(workspace_id)
+    def _maybe_prepare_merge_workspace(
+            self, repo_id, workspace_id, unused_target_ref, unused_source_ref):
+        shadow_repository_path = self._get_shadow_repository_path(
+            repo_id, workspace_id)
         if not os.path.exists(shadow_repository_path):
             self._local_clone(shadow_repository_path)
             log.debug(
@@ -697,7 +692,7 @@ class MercurialRepository(BaseRepository
 
         return shadow_repository_path
 
-    def _merge_repo(self, shadow_repository_path, target_ref,
+    def _merge_repo(self, repo_id, workspace_id, target_ref,
                     source_repo, source_ref, merge_message,
                     merger_name, merger_email, dry_run=False,
                     use_rebase=False, close_branch=False):
@@ -719,6 +714,8 @@ class MercurialRepository(BaseRepository
             return MergeResponse(
                 False, False, None, MergeFailureReason.MISSING_TARGET_REF)
 
+        shadow_repository_path = self._maybe_prepare_merge_workspace(
+            repo_id, workspace_id, target_ref, source_ref)
         shadow_repo = self._get_shadow_instance(shadow_repository_path)
 
         log.debug('Pulling in target reference %s', target_ref)
diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py
--- a/rhodecode/model/db.py
+++ b/rhodecode/model/db.py
@@ -1883,6 +1883,12 @@ class Repository(Base, BaseModel):
             return os.listdir(diff_cache_dir)
         return []
 
+    def shadow_repos(self):
+        shadow_repos_pattern = '.__shadow_repo_{}'.format(self.repo_id)
+        return [
+            x for x in os.listdir(os.path.dirname(self.repo_full_path))
+            if x.startswith(shadow_repos_pattern)]
+
     def get_new_name(self, repo_name):
         """
         returns new full repository name based on assigned group and new new
@@ -3762,7 +3768,7 @@ class PullRequest(Base, _PullRequestBase
         workspace_id = self.workspace_id
         vcs_obj = self.target_repo.scm_instance()
         shadow_repository_path = vcs_obj._get_shadow_repository_path(
-            workspace_id)
+            self.target_repo.repo_id, workspace_id)
         if os.path.isdir(shadow_repository_path):
             return vcs_obj._get_shadow_instance(shadow_repository_path)
 
diff --git a/rhodecode/model/pull_request.py b/rhodecode/model/pull_request.py
--- a/rhodecode/model/pull_request.py
+++ b/rhodecode/model/pull_request.py
@@ -583,7 +583,7 @@ class PullRequestModel(BaseModel):
 
         return commit_ids
 
-    def merge(self, pull_request, user, extras):
+    def merge_repo(self, pull_request, user, extras):
         log.debug("Merging pull request %s", pull_request.pull_request_id)
         merge_state = self._merge_pull_request(pull_request, user, extras)
         if merge_state.executed:
@@ -616,6 +616,7 @@ class PullRequestModel(BaseModel):
             }
 
         workspace_id = self._workspace_id(pull_request)
+        repo_id = pull_request.target_repo.repo_id
         use_rebase = self._use_rebase_for_merging(pull_request)
         close_branch = self._close_branch_before_merging(pull_request)
 
@@ -629,9 +630,10 @@ class PullRequestModel(BaseModel):
             target_vcs.config.set(
                 'rhodecode', 'RC_SCM_DATA', json.dumps(extras))
             merge_state = target_vcs.merge(
-                target_ref, source_vcs, pull_request.source_ref_parts,
-                workspace_id, user_name=user.username,
-                user_email=user.email, message=message, use_rebase=use_rebase,
+                repo_id, workspace_id, target_ref, source_vcs,
+                pull_request.source_ref_parts,
+                user_name=user.username, user_email=user.email,
+                message=message, use_rebase=use_rebase,
                 close_branch=close_branch)
         return merge_state
 
@@ -1328,11 +1330,13 @@ class PullRequestModel(BaseModel):
     def _refresh_merge_state(self, pull_request, target_vcs, target_reference):
         workspace_id = self._workspace_id(pull_request)
         source_vcs = pull_request.source_repo.scm_instance()
+        repo_id = pull_request.target_repo.repo_id
         use_rebase = self._use_rebase_for_merging(pull_request)
         close_branch = self._close_branch_before_merging(pull_request)
         merge_state = target_vcs.merge(
+            repo_id, workspace_id,
             target_reference, source_vcs, pull_request.source_ref_parts,
-            workspace_id, dry_run=True, use_rebase=use_rebase,
+            dry_run=True, use_rebase=use_rebase,
             close_branch=close_branch)
 
         # Do not store the response if there was an unknown error.
@@ -1398,11 +1402,12 @@ class PullRequestModel(BaseModel):
 
     def _cleanup_merge_workspace(self, pull_request):
         # Merging related cleanup
+        repo_id = pull_request.target_repo.repo_id
         target_scm = pull_request.target_repo.scm_instance()
-        workspace_id = 'pr-%s' % pull_request.pull_request_id
+        workspace_id = self._workspace_id(pull_request)
 
         try:
-            target_scm.cleanup_merge_workspace(workspace_id)
+            target_scm.cleanup_merge_workspace(repo_id, workspace_id)
         except NotImplementedError:
             pass
 
diff --git a/rhodecode/tests/__init__.py b/rhodecode/tests/__init__.py
--- a/rhodecode/tests/__init__.py
+++ b/rhodecode/tests/__init__.py
@@ -116,6 +116,13 @@ def get_new_dir(title):
     return get_normalized_path(path)
 
 
+def repo_id_generator(name):
+    numeric_hash = 0
+    for char in name:
+        numeric_hash += (ord(char))
+    return numeric_hash
+
+
 @pytest.mark.usefixtures('app', 'index_location')
 class TestController(object):
 
diff --git a/rhodecode/tests/lib/middleware/test_simplevcs.py b/rhodecode/tests/lib/middleware/test_simplevcs.py
--- a/rhodecode/tests/lib/middleware/test_simplevcs.py
+++ b/rhodecode/tests/lib/middleware/test_simplevcs.py
@@ -333,7 +333,7 @@ class TestShadowRepoExposure(object):
         workspace_id = PullRequestModel()._workspace_id(pull_request)
         target_vcs = pull_request.target_repo.scm_instance()
         vcs_repo_name = target_vcs._get_shadow_repository_path(
-            workspace_id)
+            pull_request.target_repo.repo_id, workspace_id)
 
         assert controller.vcs_repo_name == vcs_repo_name
         assert controller.url_repo_name == shadow_url
diff --git a/rhodecode/tests/models/test_pullrequest.py b/rhodecode/tests/models/test_pullrequest.py
--- a/rhodecode/tests/models/test_pullrequest.py
+++ b/rhodecode/tests/models/test_pullrequest.py
@@ -81,6 +81,7 @@ class TestPullRequestModel(object):
         self.source_commit = self.pull_request.source_ref_parts.commit_id
         self.target_commit = self.pull_request.target_ref_parts.commit_id
         self.workspace_id = 'pr-%s' % self.pull_request.pull_request_id
+        self.repo_id = self.pull_request.target_repo.repo_id
 
         @request.addfinalizer
         def cleanup_pull_request():
@@ -135,17 +136,19 @@ class TestPullRequestModel(object):
         assert pr_count == 1
 
     def test_delete_calls_cleanup_merge(self, pull_request):
+        repo_id = pull_request.target_repo.repo_id
         PullRequestModel().delete(pull_request, pull_request.author)
 
         self.workspace_remove_mock.assert_called_once_with(
-            self.workspace_id)
+            repo_id, self.workspace_id)
 
     def test_close_calls_cleanup_and_hook(self, pull_request):
         PullRequestModel().close_pull_request(
             pull_request, pull_request.author)
+        repo_id = pull_request.target_repo.repo_id
 
         self.workspace_remove_mock.assert_called_once_with(
-            self.workspace_id)
+            repo_id, self.workspace_id)
         self.hook_mock.assert_called_with(
             self.pull_request, self.pull_request.author, 'close')
 
@@ -161,9 +164,10 @@ class TestPullRequestModel(object):
         assert status is True
         assert msg.eval() == 'This pull request can be automatically merged.'
         self.merge_mock.assert_called_with(
+            self.repo_id, self.workspace_id,
             pull_request.target_ref_parts,
             pull_request.source_repo.scm_instance(),
-            pull_request.source_ref_parts, self.workspace_id, dry_run=True,
+            pull_request.source_ref_parts, dry_run=True,
             use_rebase=False, close_branch=False)
 
         assert pull_request._last_merge_source_rev == self.source_commit
@@ -190,9 +194,10 @@ class TestPullRequestModel(object):
             msg.eval() ==
             'This pull request cannot be merged because of merge conflicts.')
         self.merge_mock.assert_called_with(
+            self.repo_id, self.workspace_id,
             pull_request.target_ref_parts,
             pull_request.source_repo.scm_instance(),
-            pull_request.source_ref_parts, self.workspace_id, dry_run=True,
+            pull_request.source_ref_parts, dry_run=True,
             use_rebase=False, close_branch=False)
 
         assert pull_request._last_merge_source_rev == self.source_commit
@@ -222,9 +227,10 @@ class TestPullRequestModel(object):
             'This pull request cannot be merged because of an unhandled'
             ' exception.')
         self.merge_mock.assert_called_with(
+            self.repo_id, self.workspace_id,
             pull_request.target_ref_parts,
             pull_request.source_repo.scm_instance(),
-            pull_request.source_ref_parts, self.workspace_id, dry_run=True,
+            pull_request.source_ref_parts, dry_run=True,
             use_rebase=False, close_branch=False)
 
         assert pull_request._last_merge_source_rev is None
@@ -281,7 +287,7 @@ class TestPullRequestModel(object):
             True, True, merge_ref, MergeFailureReason.NONE)
 
         merge_extras['repository'] = pull_request.target_repo.repo_name
-        PullRequestModel().merge(
+        PullRequestModel().merge_repo(
             pull_request, pull_request.author, extras=merge_extras)
 
         message = (
@@ -295,9 +301,10 @@ class TestPullRequestModel(object):
             )
         )
         self.merge_mock.assert_called_with(
+            self.repo_id, self.workspace_id,
             pull_request.target_ref_parts,
             pull_request.source_repo.scm_instance(),
-            pull_request.source_ref_parts, self.workspace_id,
+            pull_request.source_ref_parts,
             user_name=user.username, user_email=user.email, message=message,
             use_rebase=False, close_branch=False
         )
@@ -320,7 +327,7 @@ class TestPullRequestModel(object):
             False, False, merge_ref, MergeFailureReason.MERGE_FAILED)
 
         merge_extras['repository'] = pull_request.target_repo.repo_name
-        PullRequestModel().merge(
+        PullRequestModel().merge_repo(
             pull_request, pull_request.author, extras=merge_extras)
 
         message = (
@@ -334,9 +341,10 @@ class TestPullRequestModel(object):
             )
         )
         self.merge_mock.assert_called_with(
+            self.repo_id, self.workspace_id,
             pull_request.target_ref_parts,
             pull_request.source_repo.scm_instance(),
-            pull_request.source_ref_parts, self.workspace_id,
+            pull_request.source_ref_parts,
             user_name=user.username, user_email=user.email, message=message,
             use_rebase=False, close_branch=False
         )
@@ -392,7 +400,7 @@ class TestIntegrationMerge(object):
         Session().commit()
 
         with mock.patch.dict(rhodecode.CONFIG, extra_config, clear=False):
-            merge_state = PullRequestModel().merge(
+            merge_state = PullRequestModel().merge_repo(
                 pull_request, user_admin, extras=merge_extras)
 
         assert merge_state.executed
@@ -409,7 +417,7 @@ class TestIntegrationMerge(object):
 
         with mock.patch('rhodecode.EXTENSIONS.PRE_PUSH_HOOK') as pre_pull:
             pre_pull.side_effect = RepositoryError("Disallow push!")
-            merge_status = PullRequestModel().merge(
+            merge_status = PullRequestModel().merge_repo(
                 pull_request, user_admin, extras=merge_extras)
 
         assert not merge_status.executed
@@ -429,7 +437,7 @@ class TestIntegrationMerge(object):
         merge_extras['repository'] = pull_request.target_repo.repo_name
         # TODO: johbo: Needed for sqlite, try to find an automatic way for it
         Session().commit()
-        merge_status = PullRequestModel().merge(
+        merge_status = PullRequestModel().merge_repo(
             pull_request, user_regular, extras=merge_extras)
         assert not merge_status.executed
 
diff --git a/rhodecode/tests/vcs/test_git.py b/rhodecode/tests/vcs/test_git.py
--- a/rhodecode/tests/vcs/test_git.py
+++ b/rhodecode/tests/vcs/test_git.py
@@ -566,7 +566,7 @@ TODO: To be written...
 
     def test_maybe_prepare_merge_workspace(self):
         workspace = self.repo._maybe_prepare_merge_workspace(
-            'pr2', Reference('branch', 'master', 'unused'),
+            2, 'pr2', Reference('branch', 'master', 'unused'),
             Reference('branch', 'master', 'unused'))
 
         assert os.path.isdir(workspace)
@@ -575,13 +575,13 @@ TODO: To be written...
 
         # Calling it a second time should also succeed
         workspace = self.repo._maybe_prepare_merge_workspace(
-            'pr2', Reference('branch', 'master', 'unused'),
+            2, 'pr2', Reference('branch', 'master', 'unused'),
             Reference('branch', 'master', 'unused'))
         assert os.path.isdir(workspace)
 
     def test_maybe_prepare_merge_workspace_different_refs(self):
         workspace = self.repo._maybe_prepare_merge_workspace(
-            'pr2', Reference('branch', 'master', 'unused'),
+            2, 'pr2', Reference('branch', 'master', 'unused'),
             Reference('branch', 'develop', 'unused'))
 
         assert os.path.isdir(workspace)
@@ -590,22 +590,22 @@ TODO: To be written...
 
         # Calling it a second time should also succeed
         workspace = self.repo._maybe_prepare_merge_workspace(
-            'pr2', Reference('branch', 'master', 'unused'),
+            2, 'pr2', Reference('branch', 'master', 'unused'),
             Reference('branch', 'develop', 'unused'))
         assert os.path.isdir(workspace)
 
     def test_cleanup_merge_workspace(self):
         workspace = self.repo._maybe_prepare_merge_workspace(
-            'pr3', Reference('branch', 'master', 'unused'),
+            2, 'pr3', Reference('branch', 'master', 'unused'),
             Reference('branch', 'master', 'unused'))
-        self.repo.cleanup_merge_workspace('pr3')
+        self.repo.cleanup_merge_workspace(2, 'pr3')
 
         assert not os.path.exists(workspace)
 
     def test_cleanup_merge_workspace_invalid_workspace_id(self):
         # No assert: because in case of an inexistent workspace this function
         # should still succeed.
-        self.repo.cleanup_merge_workspace('pr4')
+        self.repo.cleanup_merge_workspace(1, 'pr4')
 
     def test_set_refs(self):
         test_ref = 'refs/test-refs/abcde'
diff --git a/rhodecode/tests/vcs/test_hg.py b/rhodecode/tests/vcs/test_hg.py
--- a/rhodecode/tests/vcs/test_hg.py
+++ b/rhodecode/tests/vcs/test_hg.py
@@ -31,7 +31,7 @@ from rhodecode.lib.vcs.backends.hg impor
 from rhodecode.lib.vcs.exceptions import (
     RepositoryError, VCSError, NodeDoesNotExistError, CommitDoesNotExistError)
 from rhodecode.lib.vcs.nodes import FileNode, NodeKind, NodeState
-from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE
+from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE, repo_id_generator
 
 
 pytestmark = pytest.mark.backends("hg")
@@ -46,7 +46,6 @@ def repo_path_generator():
         i += 1
         yield '%s-%d' % (TEST_HG_REPO_CLONE, i)
 
-
 REPO_PATH_GENERATOR = repo_path_generator()
 
 
@@ -553,7 +552,7 @@ TODO: To be written...
 
     def test_maybe_prepare_merge_workspace(self):
         workspace = self.repo._maybe_prepare_merge_workspace(
-            'pr2', 'unused', 'unused2')
+            1, 'pr2', 'unused', 'unused2')
 
         assert os.path.isdir(workspace)
         workspace_repo = MercurialRepository(workspace)
@@ -561,20 +560,22 @@ TODO: To be written...
 
         # Calling it a second time should also succeed
         workspace = self.repo._maybe_prepare_merge_workspace(
-            'pr2', 'unused', 'unused2')
+            1, 'pr2', 'unused', 'unused2')
         assert os.path.isdir(workspace)
 
     def test_cleanup_merge_workspace(self):
         workspace = self.repo._maybe_prepare_merge_workspace(
-            'pr3', 'unused', 'unused2')
-        self.repo.cleanup_merge_workspace('pr3')
+            1, 'pr3', 'unused', 'unused2')
+
+        assert os.path.isdir(workspace)
+        self.repo.cleanup_merge_workspace(1, 'pr3')
 
         assert not os.path.exists(workspace)
 
     def test_cleanup_merge_workspace_invalid_workspace_id(self):
         # No assert: because in case of an inexistent workspace this function
         # should still succeed.
-        self.repo.cleanup_merge_workspace('pr4')
+        self.repo.cleanup_merge_workspace(1, 'pr4')
 
     def test_merge_target_is_bookmark(self, vcsbackend_hg):
         target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
@@ -594,10 +595,10 @@ TODO: To be written...
         target_repo.bookmark(bookmark_name)
         target_ref = Reference('book', bookmark_name, target_commit.raw_id)
         source_ref = Reference('branch', default_branch, source_commit.raw_id)
-        workspace = 'test-merge'
-
+        workspace_id = 'test-merge'
+        repo_id = repo_id_generator(target_repo.path)
         merge_response = target_repo.merge(
-            target_ref, source_repo, source_ref, workspace,
+            repo_id, workspace_id, target_ref, source_repo, source_ref,
             'test user', 'test@rhodecode.com', 'merge message 1',
             dry_run=False)
         expected_merge_response = MergeResponse(
@@ -638,10 +639,10 @@ TODO: To be written...
         source_repo._update(default_branch)
         source_repo.bookmark(bookmark_name)
         source_ref = Reference('book', bookmark_name, source_commit.raw_id)
-        workspace = 'test-merge'
-
+        workspace_id = 'test-merge'
+        repo_id = repo_id_generator(target_repo.path)
         merge_response = target_repo.merge(
-            target_ref, source_repo, source_ref, workspace,
+            repo_id, workspace_id, target_ref, source_repo, source_ref,
             'test user', 'test@rhodecode.com', 'merge message 1',
             dry_run=False)
         expected_merge_response = MergeResponse(
@@ -677,14 +678,15 @@ TODO: To be written...
 
         target_ref = Reference('branch', default_branch, target_commit.raw_id)
         source_ref = Reference('branch', default_branch, source_commit.raw_id)
-        workspace = 'test-merge'
+        workspace_id = 'test-merge'
 
         assert len(target_repo._heads(branch='default')) == 2
         expected_merge_response = MergeResponse(
             False, False, None,
             MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS)
+        repo_id = repo_id_generator(target_repo.path)
         merge_response = target_repo.merge(
-            target_ref, source_repo, source_ref, workspace,
+            repo_id, workspace_id, target_ref, source_repo, source_ref,
             'test user', 'test@rhodecode.com', 'merge message 1',
             dry_run=False)
         assert merge_response == expected_merge_response
@@ -711,10 +713,11 @@ TODO: To be written...
 
         target_ref = Reference('branch', default_branch, target_commit.raw_id)
         source_ref = Reference('book', bookmark_name, source_commit.raw_id)
-        workspace = 'test-merge'
+        repo_id = repo_id_generator(target_repo.path)
+        workspace_id = 'test-merge'
 
         merge_response = target_repo.merge(
-            target_ref, source_repo, source_ref, workspace,
+            repo_id, workspace_id, target_ref, source_repo, source_ref,
             'test user', 'test@rhodecode.com', 'merge message 1',
             dry_run=False, use_rebase=True)
 
diff --git a/rhodecode/tests/vcs/test_hg_vcsserver_cache_invalidation.py b/rhodecode/tests/vcs/test_hg_vcsserver_cache_invalidation.py
--- a/rhodecode/tests/vcs/test_hg_vcsserver_cache_invalidation.py
+++ b/rhodecode/tests/vcs/test_hg_vcsserver_cache_invalidation.py
@@ -95,7 +95,7 @@ class TestMercurialRemoteRepoInvalidatio
         references.
         """
         from rhodecode.model.pull_request import PullRequestModel
-
+        repo_id = pull_request.target_repo
         target_vcs = pull_request.target_repo.scm_instance()
         target_ref = pull_request.target_ref_parts
         source_ref = pull_request.source_ref_parts
@@ -104,7 +104,7 @@ class TestMercurialRemoteRepoInvalidatio
         pr = PullRequestModel()
         workspace_id = pr._workspace_id(pull_request)
         shadow_repository_path = target_vcs._maybe_prepare_merge_workspace(
-            workspace_id, target_ref, source_ref)
+            repo_id, workspace_id, target_ref, source_ref)
         shadow_repo = target_vcs._get_shadow_instance(shadow_repository_path)
 
         # This will populate the cache of the mercurial repository object
diff --git a/rhodecode/tests/vcs/test_repository.py b/rhodecode/tests/vcs/test_repository.py
--- a/rhodecode/tests/vcs/test_repository.py
+++ b/rhodecode/tests/vcs/test_repository.py
@@ -30,6 +30,7 @@ from rhodecode.lib.vcs.backends.base imp
 from rhodecode.lib.vcs.exceptions import VCSError, RepositoryError
 from rhodecode.lib.vcs.nodes import FileNode
 from rhodecode.tests.vcs.conftest import BackendTestMixin
+from rhodecode.tests import repo_id_generator
 
 
 @pytest.mark.usefixtures("vcs_repository_support")
@@ -268,7 +269,7 @@ class TestRepositoryGetCommonAncestor:
 
 
 @pytest.mark.backends("git", "hg")
-class TestRepositoryMerge:
+class TestRepositoryMerge(object):
     def prepare_for_success(self, vcsbackend):
         self.target_repo = vcsbackend.create_repo(number_of_commits=1)
         self.source_repo = vcsbackend.clone_repo(self.target_repo)
@@ -287,7 +288,8 @@ class TestRepositoryMerge:
             'branch', default_branch, self.target_commit.raw_id)
         self.source_ref = Reference(
             'branch', default_branch, self.source_commit.raw_id)
-        self.workspace = 'test-merge'
+        self.workspace_id = 'test-merge'
+        self.repo_id = repo_id_generator(self.target_repo.path)
 
     def prepare_for_conflict(self, vcsbackend):
         self.target_repo = vcsbackend.create_repo(number_of_commits=1)
@@ -302,13 +304,15 @@ class TestRepositoryMerge:
             'branch', default_branch, self.target_commit.raw_id)
         self.source_ref = Reference(
             'branch', default_branch, self.source_commit.raw_id)
-        self.workspace = 'test-merge'
+        self.workspace_id = 'test-merge'
+        self.repo_id = repo_id_generator(self.target_repo.path)
 
     def test_merge_success(self, vcsbackend):
         self.prepare_for_success(vcsbackend)
 
         merge_response = self.target_repo.merge(
-            self.target_ref, self.source_repo, self.source_ref, self.workspace,
+            self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
+            self.source_ref,
             'test user', 'test@rhodecode.com', 'merge message 1',
             dry_run=False)
         expected_merge_response = MergeResponse(
@@ -334,7 +338,7 @@ class TestRepositoryMerge:
             merge_response.merge_ref.commit_id)
 
         merge_response = target_repo.merge(
-            target_ref, self.source_repo, self.source_ref, self.workspace,
+            self.repo_id, self.workspace_id, target_ref, self.source_repo, self.source_ref,
             'test user', 'test@rhodecode.com', 'merge message 2',
             dry_run=False)
         expected_merge_response = MergeResponse(
@@ -353,13 +357,13 @@ class TestRepositoryMerge:
         self.prepare_for_success(vcsbackend)
 
         merge_response = self.target_repo.merge(
-            self.target_ref, self.source_repo, self.source_ref, self.workspace,
-            dry_run=True)
+            self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
+            self.source_ref, dry_run=True)
 
         # We call it twice so to make sure we can handle updates
         merge_response_update = self.target_repo.merge(
-            self.target_ref, self.source_repo, self.source_ref, self.workspace,
-            dry_run=True)
+            self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
+            self.source_ref, dry_run=True)
 
         # Multiple merges may differ in their commit id. Therefore we set the
         # commit id to `None` before comparing the merge responses.
@@ -381,13 +385,15 @@ class TestRepositoryMerge:
             False, False, None, MergeFailureReason.MERGE_FAILED)
 
         merge_response = self.target_repo.merge(
-            self.target_ref, self.source_repo, self.source_ref, self.workspace,
+            self.repo_id,  self.workspace_id, self.target_ref,
+            self.source_repo, self.source_ref,
             'test_user', 'test@rhodecode.com', 'test message', dry_run=dry_run)
         assert merge_response == expected_merge_response
 
         # We call it twice so to make sure we can handle updates
         merge_response = self.target_repo.merge(
-            self.target_ref, self.source_repo, self.source_ref, self.workspace,
+            self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
+            self.source_ref,
             'test_user', 'test@rhodecode.com', 'test message', dry_run=dry_run)
         assert merge_response == expected_merge_response
 
@@ -400,8 +406,8 @@ class TestRepositoryMerge:
             self.target_ref.type, self.target_ref.name, '0' * 40)
 
         merge_response = self.target_repo.merge(
-            target_ref, self.source_repo, self.source_ref, self.workspace,
-            dry_run=True)
+            self.repo_id, self.workspace_id, target_ref, self.source_repo,
+            self.source_ref, dry_run=True)
 
         assert merge_response == expected_merge_response
 
@@ -414,7 +420,8 @@ class TestRepositoryMerge:
             self.source_ref.type, 'not_existing', self.source_ref.commit_id)
 
         merge_response = self.target_repo.merge(
-            self.target_ref, self.source_repo, source_ref, self.workspace,
+            self.repo_id, self.workspace_id, self.target_ref,
+            self.source_repo, source_ref,
             dry_run=True)
 
         assert merge_response == expected_merge_response
@@ -427,29 +434,38 @@ class TestRepositoryMerge:
         with mock.patch.object(self.target_repo, '_merge_repo',
                                side_effect=RepositoryError()):
             merge_response = self.target_repo.merge(
-                self.target_ref, self.source_repo, self.source_ref,
-                self.workspace, dry_run=True)
+                self.repo_id, self.workspace_id, self.target_ref,
+                self.source_repo, self.source_ref,
+                dry_run=True)
 
         assert merge_response == expected_merge_response
 
     def test_merge_invalid_user_name(self, vcsbackend):
         repo = vcsbackend.create_repo(number_of_commits=1)
         ref = Reference('branch', 'master', 'not_used')
+        workspace_id = 'test-errors-in-merge'
+        repo_id = repo_id_generator(workspace_id)
         with pytest.raises(ValueError):
-            repo.merge(ref, self, ref, 'workspace_id')
+            repo.merge(repo_id,  workspace_id, ref, self, ref)
 
     def test_merge_invalid_user_email(self, vcsbackend):
         repo = vcsbackend.create_repo(number_of_commits=1)
         ref = Reference('branch', 'master', 'not_used')
+        workspace_id = 'test-errors-in-merge'
+        repo_id = repo_id_generator(workspace_id)
         with pytest.raises(ValueError):
-            repo.merge(ref, self, ref, 'workspace_id', 'user name')
+            repo.merge(
+                repo_id,  workspace_id, ref, self, ref, 'user name')
 
     def test_merge_invalid_message(self, vcsbackend):
         repo = vcsbackend.create_repo(number_of_commits=1)
         ref = Reference('branch', 'master', 'not_used')
+        workspace_id = 'test-errors-in-merge'
+        repo_id = repo_id_generator(workspace_id)
         with pytest.raises(ValueError):
             repo.merge(
-                ref, self, ref, 'workspace_id', 'user name', 'user@email.com')
+                repo_id, workspace_id, ref, self, ref,
+                'user name', 'user@email.com')
 
 
 @pytest.mark.usefixtures("vcs_repository_support")
@@ -505,7 +521,7 @@ class TestRepositoryStrip(BackendTestMix
 
 
 @pytest.mark.backends('hg', 'git')
-class TestRepositoryPull:
+class TestRepositoryPull(object):
 
     def test_pull(self, vcsbackend):
         source_repo = vcsbackend.repo