diff --git a/experiments/historical_build.py b/experiments/historical_build.py
index b4e0aa0ddb91ccbf84f30dc7736be77d99c9f21f..ed365361383473f922a08f67870242ecb71bad3b 100755
--- a/experiments/historical_build.py
+++ b/experiments/historical_build.py
@@ -29,6 +29,48 @@ class HistoricalCompilation(Experiment, ClangHashHelper):
         "stats": File("summary.dict"),
     }
 
+    def build_parent(self, commit, from_scratch = False):
+        def eq_hash(a, b):
+            if len(a) == 0 or len(b) == 0:
+                return
+            if len(a) > len(b):
+                return a.startswith(b)
+            else:
+                return b.startswith(a)
+
+        src_path = self.project.path
+
+        if from_scratch:
+            shell("cd %s; git clean -dfx", src_path)
+            logging.info("Parent [%s^]: clean build", commit)
+            shell("cd %s; git reset --hard %s^", src_path, commit)
+            info = {"commit": commit + "^"}
+            self.call_configure(src_path)
+            self.rebuild(src_path, info, True)
+            # Did initial commit fail? Try again
+            if info.get("failed"):
+                logging.info("Parent[%s^]: failed" commit)
+                return False
+            return True
+        else:
+            (lines, _) = shell("cd %s; git rev-parse %s^",
+                               src_path, commit)
+            parent_revision = lines[0].strip()
+            if self.current_revision and eq_hash(self.current_revision, parent_revision):
+                logging.info("Parent[%s^]: resuse good parent", commit)
+                return True
+            else:
+                logging.info("Parent[%s^]: resuse similar build directory", commit)
+                shell("cd %s; git reset --hard %s^", src_path, commit)
+                info = {"commit": commit +"^"}
+                self.call_reconfigure(src_path)
+                self.rebuild(src_path, info, True)
+                # Did initial commit fail? Try again
+                if info.get("failed"):
+                    return self.build_parent(commit, from_scratch=True)
+                return True
+
+
     def run(self):
         # Determine the mode
         modes = ('normal', 'ccache', 'clang-hash', 'ccache-clang-hash')
@@ -47,37 +89,51 @@ class HistoricalCompilation(Experiment, ClangHashHelper):
                            'builds': []}
 
         with self.project as src_path:
-            (commits, _) = shell("cd %s; git log --oneline --topo-order", src_path)
-            commits = [x.split(" ", 1) for x in reversed(commits)]
+            (commits, _) = shell("cd %s; git log --no-merges --oneline --topo-order --format='%%H %%P %%s'", src_path)
+            # [0] is hash. [1] is parent, [2] rest
+            commits = [x.split(" ", 2) for x in reversed(commits)]
             commits = commits[-self.commits.value:]
 
+            self.current_revision = None
+
             # First, we redirect all calls to the compiler to our
             # clang hash wrapper
             self.setup_compiler_paths(cl_path)
 
-            while True:
-                commit = commits.pop(0)
-                logging.info("Build: %s", commit)
-                shell("cd %s; git clean -dfx; git reset --hard %s", src_path, commit[0])
-                info = {"commit": "FRESH_BUILD"}
-                            # Initial build of the given project
-                self.call_configure(src_path)
-                self.rebuild(src_path, info, True)
-                # Did initial commit fail? Try again
-                if "failed" in info:
-                    continue
-                self.build_info["builds"].append(info)
-                break
-
             time = 0
-            for commit in commits:
+            while commits:
+                # Search for a child of the current revision
+                commit = None
+                if self.current_revision:
+                    for idx in range(0, len(commits)):
+                        if commits[idx][1] == self.current_revision:
+                            commit = commits[idx]
+                            del commits[idx]
+                            break
+                # No Child found -> Take the first one.
+                if not commit:
+                    commit = commits.pop(0)
+
+                info = {"commit": commit[0], "summary": commit[2]}
+
+                # First, we build the parent. In a total linear
+                # history, this is a NOP. Otherwise, we try to reset
+                # to the actual parent, and rebuild the project. This
+                # may fail, since the current commit might fix this.
+                self.build_parent(commit[0])
+
                 shell("cd %s; git reset --hard %s", src_path, commit[0])
-                info = {"commit": commit[0], "summary": commit[1]}
                 self.call_reconfigure(src_path)
                 self.rebuild(src_path, info, fail_ok=True)
+
                 self.build_info["builds"].append(info)
                 if not info.get("failed"):
                     time += info['build-time'] / 1e9
+                    # Build was good. Remember that.
+                    self.current_revision = commit[0]
+                else:
+                    self.current_revision = None
+
             logging.info("Rebuild for %d commits takes %f minutes",
                          self.commits.value, time/60.)
 
diff --git a/experiments/lib.py b/experiments/lib.py
index 1285b5b05a4e2ec3614c8c01dc1e8a3708943390..bc70310ae0c34d6abe6a93feb59c0472154e98c3 100644
--- a/experiments/lib.py
+++ b/experiments/lib.py
@@ -51,7 +51,10 @@ class ClangHashHelper:
         elif self.project_name() in ("musl", "bash", "samba"):
             shell("cd %s; ./configure", path)
         elif self.project_name() in ("cpython",):
-            shell("cd %s; mkdir build; cd build; ../configure", path)
+            shell("cd %s; mkdir -p build build/Modules;", path)
+            shell("cd %s; cp -u Modules/Setup.dist build/Modules/Setup", path)
+            shell("cd %s; cd build; ../configure", path)
+
         elif self.project_name() in ('mbedtls'):
             shell("cd %s; mkdir build; cd build; cmake .. -DCMAKE_C_COMPILER=$CC -DENABLE_PROGRAMS=OFF", path)
         elif self.project_name() in ('lua',):
@@ -72,7 +75,8 @@ class ClangHashHelper:
         if self.project_name() in ('lua',):
             self.call_configure(path)
         if self.project_name() in ('cpython',):
-            shell("cd %s/build; make config.status", path)
+            shell("cd %s; mkdir -p build/Modules; cp -u Modules/Setup.dist build/Modules/Setup", path)
+
 
     def call_make(self, path):
         if self.project_name() in ("mbedtls", "cpython"):