diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -347,6 +347,12 @@ class filtervfs(abstractvfs):
     def __call__(self, path, *args, **kwargs):
         return self._orig(self._filter(path), *args, **kwargs)
 
+    def join(self, path):
+        if path:
+            return self._orig.join(self._filter(path))
+        else:
+            return self._orig.join(path)
+
 filteropener = filtervfs
 
 def canonpath(root, cwd, myname, auditor=None):
diff --git a/mercurial/statichttprepo.py b/mercurial/statichttprepo.py
--- a/mercurial/statichttprepo.py
+++ b/mercurial/statichttprepo.py
@@ -74,6 +74,12 @@ def build_opener(ui, authinfo):
             f = "/".join((self.base, urllib.quote(path)))
             return httprangereader(f, urlopener)
 
+        def join(self, path):
+            if path:
+                return os.path.join(self.base, path)
+            else:
+                return self.base
+
     return statichttpvfs
 
 class statichttppeer(localrepo.localpeer):
diff --git a/mercurial/store.py b/mercurial/store.py
--- a/mercurial/store.py
+++ b/mercurial/store.py
@@ -441,6 +441,12 @@ class _fncachevfs(scmutil.abstractvfs):
             self.fncache.add(path)
         return self.vfs(self.encode(path), mode, *args, **kw)
 
+    def join(self, path):
+        if path:
+            return self.vfs.join(self.encode(path))
+        else:
+            return self.vfs.join(path)
+
 class fncachestore(basicstore):
     def __init__(self, path, vfstype, dotencode):
         if dotencode: