diff --git a/cps.install b/cps.install
index 5727960..e4954d4 100644
--- a/cps.install
+++ b/cps.install
@@ -497,3 +497,80 @@ function cps_update_7106() {
   db_add_primary_key('cps_entity', array('changeset_id', 'entity_type', 'entity_id'));
   db_add_index('cps_entity', 'entity', array('entity_type', 'entity_id'));
 }
+
+/**
+ * Add historical information for changeset affected by #2428323.
+ */
+function cps_update_7107() {
+  $types = cps_get_supported();
+  // Get an array of entity types where there has never been an entity of that
+  // type edited in a changeset. This saves unnecessary queries later on.
+  $exclude_types = [];
+  foreach ($types as $type) {
+    if (!db_query_range('SELECT 1 FROM {cps_entity} WHERE entity_type = :entity_type AND published = 0', 0, 1, array(':entity_type' => $entity_type))->fetchField()) {
+      $exclude_types[] = $type;
+    }
+  }
+  $entity_info = entity_get_info();
+  $changeset_result = db_query('SELECT changeset_id, published FROM {cps_changeset} WHERE status = :status', array(':status' => 'archived'));
+
+  $transaction = db_transaction();
+  try {
+    foreach ($changeset_result as $changeset) {
+      foreach ($types as $type) {
+        $base_table = $entity_info[$type]['base table'];
+        $id_key = $entity_info[$type]['entity keys']['id'];
+        $revision_key = $entity_info[$type]['entity keys']['revision'];
+        // Find all entities missing from this changeset.
+        $from_query = db_select('cps_entity', 'cps_entity')
+          ->fields('cps_entity', ['entity_id'])
+          ->condition('changeset_id', $changeset->changeset_id)
+          ->condition('entity_type', $type);
+        $result = db_select($base_table, 'base')
+          ->fields('base', [$id_key, $revision_key])
+          ->condition($id_key, $from_query, 'NOT IN')
+          ->execute();
+
+        foreach ($result as $record) {
+          $vid = NULL;
+          $previous_args = array(
+            ':id' => $record->{$id_key},
+            ':published' => $changeset->published,
+            ':type' => $type,
+            ':status' => 'archived',
+          );
+          // If this entity type has never been used in a changeset, just use
+          // the current version ID.
+          if (in_array($type, $exclude_types)) {
+            $vid = $record->{$revision_key};
+          }
+          // If the entity was edited in a changeset published prior to this
+          // one, then the version ID from that changeset should be used. This
+          // ensures that entities that have been edited in multiple changesets
+          // have the correct historical state - just taking the most recent vid
+          // would not be correct in this case.
+          else if ($vid = db_query_range('SELECT revision_id FROM {cps_entity} ce INNER JOIN cps_changeset cc ON ce.changeset_id = cc.changeset_id WHERE ce.entity_id = :id AND ce.entity_type = :type AND ce.published = 0 AND cc.published < :published AND cc.status = :status ORDER BY cc.published DESC', 0, 1, $previous_args)->fetchField()) {
+            // Assignment happens in the if statement, nothing else to do here.
+          }
+          // Otherwise use the current revision ID.
+          else {
+            $vid = $record->{$revision_key};
+          }
+
+          db_insert('cps_entity')
+            ->fields(array(
+              'entity_type' => $type,
+              'entity_id' => $record->{$id_key},
+              'revision_id' => $vid,
+              'changeset_id' => $changeset->changeset_id,
+              'published' => TRUE,
+            ))->execute();
+        }
+      }
+    }
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    throw $e;
+  }
+}
