diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000000000000000000000000000000000..8ac2ef6863a39d689c11e9dc96261f66dcc882a5
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+kwant/_kwant_version.py export-subst
diff --git a/kwant/_kwant_version.py b/kwant/_kwant_version.py
index 9530ac998c43053c49ccbf5ede5955b72deba379..1507e6a4d5709e3a04b501c2f78826f71113ca42 100644
--- a/kwant/_kwant_version.py
+++ b/kwant/_kwant_version.py
@@ -2,3 +2,7 @@
 # distribution is made.  The magic value "__use_git__" is interpreted by
 # _common.py in this directory.
 version = "__use_git__"
+
+# These values are only set if the distribution was created with 'git archive'
+refnames = "$Format:%D$"
+git_hash = "$Format:%h$"
diff --git a/kwant/version.py b/kwant/version.py
index c7da0e294a86a7c242be1681b01bca6a20f705cd..48575383d159e6cb87540787bb79a74e3aefbd7c 100644
--- a/kwant/version.py
+++ b/kwant/version.py
@@ -83,6 +83,34 @@ def get_version_from_git():
     return "".join(version)
 
 
+# TODO: change this logic when there is a git pretty-format
+#       that gives the same output as 'git describe'.
+#       Currently we can only tell the tag the current commit is
+#       pointing to, or its hash (with no version info)
+#       if it is not tagged.
+def get_version_from_git_archive(version_info):
+    try:
+        refnames = version_info['refnames']
+        git_hash = version_info['git_hash']
+    except KeyError:
+        # These fields are not present if we are running from an sdist.
+        # Execution should never reach here, though
+        return None
+
+    if git_hash.startswith('$Format') or refnames.startswith('$Format'):
+        # variables not expanded during 'git archive'
+        return None
+
+    VTAG = 'tag: v'  # Our version tags always start with 'v'
+    refs = set(r.strip() for r in refnames.split(","))
+    version_tags = set(r[len(VTAG):] for r in refs if r.startswith(VTAG))
+    if version_tags:
+        release, *_ = sorted(version_tags)  # prefer e.g. "2.0" over "2.0rc1"
+        return release
+    else:
+        return ''.join(('unknown', '+g', git_hash))
+
+
 def init(version_file='_kwant_version.py'):
     global version, version_is_from_git
     version_info = {}
@@ -92,6 +120,8 @@ def init(version_file='_kwant_version.py'):
     version_is_from_git = (version == "__use_git__")
     if version_is_from_git:
         version = get_version_from_git()
+        if not version:
+            version = get_version_from_git_archive(version_info)
         if not version:
             version = "unknown"
 
diff --git a/setup.py b/setup.py
index 7165e4867cb7dc4088628c5b88a7aa61d7b82c7f..00263e9883d9048b62a3a49298138e2b5e159ec1 100755
--- a/setup.py
+++ b/setup.py
@@ -15,7 +15,7 @@ import sys
 import re
 import os
 import glob
-import imp
+import importlib
 import subprocess
 import configparser
 import collections
@@ -123,10 +123,9 @@ def check_versions():
 
     # Let Kwant itself determine its own version.  We cannot simply import
     # kwant, as it is not built yet.
-    _dont_write_bytecode_saved = sys.dont_write_bytecode
-    sys.dont_write_bytecode = True
-    version_module = imp.load_source('version', 'kwant/version.py')
-    sys.dont_write_bytecode = _dont_write_bytecode_saved
+    spec = importlib.util.spec_from_file_location('version', 'kwant/version.py')
+    version_module = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(version_module)
 
     version_module.ensure_python()
     version = version_module.version