diff --git a/core/modules/book/book.info.yml b/core/modules/book/book.info.yml
index a19e9a0..e70180f 100644
--- a/core/modules/book/book.info.yml
+++ b/core/modules/book/book.info.yml
@@ -7,4 +7,5 @@ core: 8.x
 dependencies:
   - menu_link
   - node
+  - node_revision
 configure: admin/structure/book/settings
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
index 965c44d..7e648f9 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
@@ -21,7 +21,7 @@
   *
   * @var array
   */
-  public static $modules = array('file', 'file_module_test', 'field_ui');
+  public static $modules = array('node', 'node_revision', 'file', 'file_module_test', 'field_ui');
 
   protected $admin_user;
 
diff --git a/core/modules/node/css/node.admin.css b/core/modules/node/css/node.admin.css
deleted file mode 100644
index 101a38d..0000000
--- a/core/modules/node/css/node.admin.css
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @file
- * Styles for administration pages.
- */
-
-/**
- * Revisions overview screen.
- */
-.revision-current {
-  background: #ffc;
-}
diff --git a/core/modules/node/lib/Drupal/node/Access/NodeRevisionAccessCheck.php b/core/modules/node/lib/Drupal/node/Access/NodeRevisionAccessCheck.php
deleted file mode 100644
index aca491d..0000000
--- a/core/modules/node/lib/Drupal/node/Access/NodeRevisionAccessCheck.php
+++ /dev/null
@@ -1,158 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\node\Access\NodeRevisionAccessCheck.
- */
-
-namespace Drupal\node\Access;
-
-use Drupal\Core\Access\AccessCheckInterface;
-use Drupal\Core\Database\Connection;
-use Drupal\Core\Entity\EntityManager;
-use Drupal\Core\Session\AccountInterface;
-use Drupal\node\NodeInterface;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\Routing\Route;
-
-/**
- * Provides an access checker for node revisions.
- */
-class NodeRevisionAccessCheck implements AccessCheckInterface {
-
-  /**
-   * The node storage.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
-   */
-  protected $nodeStorage;
-
-  /**
-   * The node access controller.
-   *
-   * @var \Drupal\Core\Entity\EntityAccessControllerInterface
-   */
-  protected $nodeAccess;
-
-  /**
-   * The database connection.
-   *
-   * @var \Drupal\Core\Database\Connection
-   */
-  protected $connection;
-
-  /**
-   * A static cache of access checks.
-   *
-   * @var array
-   */
-  protected $access = array();
-
-  /**
-   * Constructs a new NodeRevisionAccessCheck.
-   *
-   * @param \Drupal\Core\Entity\EntityManager $entity_manager
-   *   The entity manager.
-   * @param \Drupal\Core\Database\Connection $connection
-   *   The database connection.
-   */
-  public function __construct(EntityManager $entity_manager, Connection $connection) {
-    $this->nodeStorage = $entity_manager->getStorageController('node');
-    $this->nodeAccess = $entity_manager->getAccessController('node');
-    $this->connection = $connection;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function applies(Route $route) {
-    return array_key_exists('_access_node_revision', $route->getRequirements());
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function access(Route $route, Request $request) {
-    $revision = $this->nodeStorage->loadRevision($request->attributes->get('node_revision'));
-    return $this->checkAccess($revision, $route->getRequirement('_access_node_revision')) ? static::ALLOW : static::DENY;
-  }
-
-  /**
-   * Checks node revision access.
-   *
-   * @param \Drupal\node\NodeInterface $node
-   *   The node to check.
-   * @param string $op
-   *   (optional) The specific operation being checked. Defaults to 'view.'
-   * @param \Drupal\Core\Session\AccountInterface|null $account
-   *   (optional) A user object representing the user for whom the operation is
-   *   to be performed. Determines access for a user other than the current user.
-   *   Defaults to NULL.
-   * @param string|null $langcode
-   *   (optional) Language code for the variant of the node. Different language
-   *   variants might have different permissions associated. If NULL, the
-   *   original langcode of the node is used. Defaults to NULL.
-   *
-   * @return bool
-   *   TRUE if the operation may be performed, FALSE otherwise.
-   */
-  public function checkAccess(NodeInterface $node, $op = 'view', AccountInterface $account = NULL, $langcode = NULL) {
-    $map = array(
-      'view' => 'view all revisions',
-      'update' => 'revert all revisions',
-      'delete' => 'delete all revisions',
-    );
-    $bundle = $node->bundle();
-    $type_map = array(
-      'view' => "view $bundle revisions",
-      'update' => "revert $bundle revisions",
-      'delete' => "delete $bundle revisions",
-    );
-
-    if (!$node || !isset($map[$op]) || !isset($type_map[$op])) {
-      // If there was no node to check against, or the $op was not one of the
-      // supported ones, we return access denied.
-      return FALSE;
-    }
-
-    if (!isset($account)) {
-      $account = $GLOBALS['user'];
-    }
-
-    // If no language code was provided, default to the node revision's langcode.
-    if (empty($langcode)) {
-      $langcode = $node->language()->id;
-    }
-
-    // Statically cache access by revision ID, language code, user account ID,
-    // and operation.
-    $cid = $node->getRevisionId() . ':' . $langcode . ':' . $account->id() . ':' . $op;
-
-    if (!isset($this->access[$cid])) {
-      // Perform basic permission checks first.
-      if (!user_access($map[$op], $account) && !user_access($type_map[$op], $account) && !user_access('administer nodes', $account)) {
-        return $this->access[$cid] = FALSE;
-      }
-
-      // There should be at least two revisions. If the vid of the given node
-      // and the vid of the default revision differ, then we already have two
-      // different revisions so there is no need for a separate database check.
-      // Also, if you try to revert to or delete the default revision, that's
-      // not good.
-      if ($node->isDefaultRevision() && ($this->connection->query('SELECT COUNT(*) FROM {node_field_revision} WHERE nid = :nid AND default_langcode = 1', array(':nid' => $node->id()))->fetchField() == 1 || $op == 'update' || $op == 'delete')) {
-        $this->access[$cid] = FALSE;
-      }
-      elseif (user_access('administer nodes', $account)) {
-        $this->access[$cid] = TRUE;
-      }
-      else {
-        // First check the access to the default revision and finally, if the
-        // node passed in is not the default revision then access to that, too.
-        $this->access[$cid] = $this->nodeAccess->access($this->nodeStorage->load($node->id()), $op, $langcode, $account) && ($node->isDefaultRevision() || $this->nodeAccess->access($node, $op, $langcode, $account));
-      }
-    }
-
-    return $this->access[$cid];
-  }
-
-}
diff --git a/core/modules/node/lib/Drupal/node/Form/NodeRevisionDeleteForm.php b/core/modules/node/lib/Drupal/node/Form/NodeRevisionDeleteForm.php
deleted file mode 100644
index 8c06d49..0000000
--- a/core/modules/node/lib/Drupal/node/Form/NodeRevisionDeleteForm.php
+++ /dev/null
@@ -1,130 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\node\Form\NodeRevisionDeleteForm.
- */
-
-namespace Drupal\node\Form;
-
-use Drupal\Core\Controller\ControllerInterface;
-use Drupal\Core\Database\Connection;
-use Drupal\Core\Entity\EntityStorageControllerInterface;
-use Drupal\Core\Form\ConfirmFormBase;
-use Drupal\node\NodeInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * Provides a form for reverting a node revision.
- */
-class NodeRevisionDeleteForm extends ConfirmFormBase implements ControllerInterface {
-
-  /**
-   * The node revision.
-   *
-   * @var \Drupal\node\NodeInterface
-   */
-  protected $revision;
-
-  /**
-   * The node storage.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
-   */
-  protected $nodeStorage;
-
-  /**
-   * The node type storage.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
-   */
-  protected $nodeTypeStorage;
-
-  /**
-   * The database connection.
-   *
-   * @var \Drupal\Core\Database\Connection
-   */
-  protected $connection;
-
-  /**
-   * Constructs a new NodeRevisionDeleteForm.
-   *
-   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $node_storage
-   *   The node storage.
-   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $node_type_storage
-   *   The node type storage.
-   * @param \Drupal\Core\Database\Connection $connection
-   *   The database connection.
-   */
-  public function __construct(EntityStorageControllerInterface $node_storage, EntityStorageControllerInterface $node_type_storage, Connection $connection) {
-    $this->nodeStorage = $node_storage;
-    $this->nodeTypeStorage = $node_type_storage;
-    $this->connection = $connection;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    $entity_manager = $container->get('plugin.manager.entity');
-    return new static(
-      $entity_manager->getStorageController('node'),
-      $entity_manager->getStorageController('node_type'),
-      $container->get('database')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormID() {
-    return 'node_revision_delete_confirm';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getQuestion() {
-    return t('Are you sure you want to delete the revision from %revision-date?', array('%revision-date' => format_date($this->revision->getRevisionCreationTime())));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCancelPath() {
-    return 'node/' . $this->revision->id() . '/revisions';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConfirmText() {
-    return t('Delete');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, array &$form_state, Request $request = NULL, $node_revision = NULL) {
-    $this->revision = $this->nodeStorage->loadRevision($node_revision);
-    return parent::buildForm($form, $form_state, $request);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, array &$form_state) {
-    $this->nodeStorage->deleteRevision($this->revision->getRevisionId());
-
-    watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $this->revision->bundle(), '%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()));
-    $node_type = $this->nodeTypeStorage->load($this->revision->bundle())->label();
-    drupal_set_message(t('Revision from %revision-date of @type %title has been deleted.', array('%revision-date' => format_date($this->revision->getRevisionCreationTime()), '@type' => $node_type, '%title' => $this->revision->label())));
-    $form_state['redirect'] = 'node/' . $this->revision->id();
-    if ($this->connection->query('SELECT COUNT(DISTINCT vid) FROM {node_field_revision} WHERE nid = :nid', array(':nid' => $this->revision->id()))->fetchField() > 1) {
-      $form_state['redirect'] .= '/revisions';
-    }
-  }
-
-}
diff --git a/core/modules/node/lib/Drupal/node/Form/NodeRevisionRevertForm.php b/core/modules/node/lib/Drupal/node/Form/NodeRevisionRevertForm.php
deleted file mode 100644
index d4c69ec..0000000
--- a/core/modules/node/lib/Drupal/node/Form/NodeRevisionRevertForm.php
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\node\Form\NodeRevisionDeleteForm.
- */
-
-namespace Drupal\node\Form;
-
-use Drupal\Core\Controller\ControllerInterface;
-use Drupal\Core\Entity\EntityStorageControllerInterface;
-use Drupal\Core\Form\ConfirmFormBase;
-use Drupal\node\NodeInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * Provides a form for reverting a node revision.
- */
-class NodeRevisionRevertForm extends ConfirmFormBase implements ControllerInterface {
-
-  /**
-   * The node revision.
-   *
-   * @var \Drupal\node\NodeInterface
-   */
-  protected $revision;
-
-  /**
-   * The node storage.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
-   */
-  protected $nodeStorage;
-
-  /**
-   * Constructs a new NodeRevisionRevertForm.
-   *
-   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $node_storage
-   *   The node storage.
-   */
-  public function __construct(EntityStorageControllerInterface $node_storage) {
-    $this->nodeStorage = $node_storage;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('plugin.manager.entity')->getStorageController('node')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormID() {
-    return 'node_revision_revert_confirm';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getQuestion() {
-    return t('Are you sure you want to revert to the revision from %revision-date?', array('%revision-date' => format_date($this->revision->getRevisionCreationTime())));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCancelPath() {
-    return 'node/' . $this->revision->id() . '/revisions';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConfirmText() {
-    return t('Revert');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getDescription() {
-    return '';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, array &$form_state, Request $request = NULL, $node_revision = NULL) {
-    $this->revision = $this->nodeStorage->loadRevision($node_revision);
-    return parent::buildForm($form, $form_state, $request);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, array &$form_state) {
-    $this->revision->setNewRevision();
-    // Make this the new default revision for the node.
-    $this->revision->isDefaultRevision(TRUE);
-
-    // The revision timestamp will be updated when the revision is saved. Keep the
-    // original one for the confirmation message.
-    $original_revision_timestamp = $this->revision->getRevisionCreationTime();
-
-    $this->revision->log = t('Copy of the revision from %date.', array('%date' => format_date($original_revision_timestamp)));
-
-    $this->revision->save();
-
-    watchdog('content', '@type: reverted %title revision %revision.', array('@type' => $this->revision->bundle(), '%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()));
-    drupal_set_message(t('@type %title has been reverted back to the revision from %revision-date.', array('@type' => node_get_type_label($this->revision), '%title' => $this->revision->label(), '%revision-date' => format_date($original_revision_timestamp))));
-    $form_state['redirect'] = 'node/' . $this->revision->id() . '/revisions';
-  }
-
-}
diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index 814d937..a0faec8 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -126,44 +126,6 @@ public function form(array $form, array &$form_state) {
       '#weight' => 99,
     );
 
-    // Add a log field if the "Create new revision" option is checked, or if
-    // the current user has the ability to check that option.
-    $form['revision_information'] = array(
-      '#type' => 'details',
-      '#group' => 'advanced',
-      '#title' => t('Revision information'),
-      // Collapsed by default when "Create new revision" is unchecked.
-      '#collapsed' => !$node->isNewRevision(),
-      '#attributes' => array(
-        'class' => array('node-form-revision-information'),
-      ),
-      '#attached' => array(
-        'js' => array(drupal_get_path('module', 'node') . '/node.js'),
-      ),
-      '#weight' => 20,
-      '#access' => $node->isNewRevision() || user_access('administer nodes'),
-    );
-
-    $form['revision_information']['revision']['revision'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Create new revision'),
-      '#default_value' => $node->isNewRevision(),
-      '#access' => user_access('administer nodes'),
-    );
-
-    $form['revision_information']['revision']['log'] = array(
-      '#type' => 'textarea',
-      '#title' => t('Revision log message'),
-      '#rows' => 4,
-      '#default_value' => !empty($node->log) ? $node->log : '',
-      '#description' => t('Briefly describe the changes you have made.'),
-      '#states' => array(
-        'visible' => array(
-          ':input[name="revision"]' => array('checked' => TRUE),
-        ),
-      ),
-    );
-
     // Node author information for administrators.
     $form['author'] = array(
       '#type' => 'details',
@@ -370,11 +332,6 @@ public function submit(array $form, array &$form_state) {
     // Build the node object from the submitted values.
     $node = parent::submit($form, $form_state);
 
-    // Save as a new revision if requested to do so.
-    if (!empty($form_state['values']['revision'])) {
-      $node->setNewRevision();
-    }
-
     node_submit($node);
     foreach (module_implements('node_submit') as $module) {
       $function = $module . '_node_submit';
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionPermissionsTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionPermissionsTest.php
deleted file mode 100644
index e0db862..0000000
--- a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionPermissionsTest.php
+++ /dev/null
@@ -1,164 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\node\Tests\NodeRevisionPermissionsTest.
- */
-
-namespace Drupal\node\Tests;
-
-/**
- * Tests user permissions for node revisions.
- */
-class NodeRevisionPermissionsTest extends NodeTestBase {
-  protected $node_revisions = array();
-  protected $accounts = array();
-
-  // Map revision permission names to node revision access ops.
-  protected $map = array(
-    'view' => 'view all revisions',
-    'update' => 'revert all revisions',
-    'delete' => 'delete all revisions',
-  );
-
-  // Map revision permission names to node type revision access ops.
-  protected $type_map = array(
-    'view' => 'view page revisions',
-    'update' => 'revert page revisions',
-    'delete' => 'delete page revisions',
-  );
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Node revision permissions',
-      'description' => 'Tests user permissions for node revision operations.',
-      'group' => 'Node',
-    );
-  }
-
-  function setUp() {
-    parent::setUp();
-
-    $types = array('page', 'article');
-
-    foreach ($types as $type) {
-      // Create a node with several revisions.
-      $nodes[$type] = $this->drupalCreateNode(array('type' => $type));
-      $this->node_revisions[$type][] = $nodes[$type];
-
-      for ($i = 0; $i < 3; $i++) {
-        // Create a revision for the same nid and settings with a random log.
-        $revision = clone $nodes[$type];
-        $revision->setNewRevision();
-        $revision->log = $this->randomName(32);
-        $revision->save();
-        $this->node_revisions[$type][] = $revision;
-      }
-    }
-  }
-
-  /**
-   * Tests general revision access permissions.
-   */
-  function testNodeRevisionAccessAnyType() {
-    // Create three users, one with each revision permission.
-    foreach ($this->map as $op => $permission) {
-      // Create the user.
-      $account = $this->drupalCreateUser(
-        array(
-          'access content',
-          'edit any page content',
-          'delete any page content',
-          $permission,
-        )
-      );
-      $account->op = $op;
-      $this->accounts[] = $account;
-    }
-
-    // Create an admin account (returns TRUE for all revision permissions).
-    $admin_account = $this->drupalCreateUser(array('access content', 'administer nodes'));
-    $admin_account->is_admin = TRUE;
-    $this->accounts['admin'] = $admin_account;
-    $accounts['admin'] = $admin_account;
-
-    // Create a normal account (returns FALSE for all revision permissions).
-    $normal_account = $this->drupalCreateUser();
-    $normal_account->op = FALSE;
-    $this->accounts[] = $normal_account;
-    $accounts[] = $normal_account;
-    $revision = $this->node_revisions['page'][1];
-
-    $parameters = array(
-      'op' => array_keys($this->map),
-      'account' => $this->accounts,
-    );
-
-    $permutations = $this->generatePermutations($parameters);
-
-    foreach ($permutations as $case) {
-      // Skip this test if there are no revisions for the node.
-      if (!($revision->isDefaultRevision() && (db_query('SELECT COUNT(vid) FROM {node_field_revision} WHERE nid = :nid', array(':nid' => $revision->nid))->fetchField() == 1 || $case['op'] == 'update' || $case['op'] == 'delete'))) {
-        if (!empty($case['account']->is_admin) || user_access($this->map[$case['op']], $case['account'])) {
-          $this->assertTrue(_node_revision_access($revision, $case['op'], $case['account']), "{$this->map[$case['op']]} granted.");
-        }
-        else {
-          $this->assertFalse(_node_revision_access($revision, $case['op'], $case['account']), "{$this->map[$case['op']]} not granted.");
-        }
-      }
-    }
-
-    // Test that access is FALSE for a node administrator with an invalid $node
-    // or $op parameters.
-    $admin_account = $accounts['admin'];
-    $this->assertFalse(_node_revision_access($revision, 'invalid-op', $admin_account), '_node_revision_access() returns FALSE with an invalid op.');
-  }
-
-  /**
-   * Tests revision access permissions for a specific content type.
-   */
-  function testNodeRevisionAccessPerType() {
-    // Create three users, one with each revision permission.
-    foreach ($this->type_map as $op => $permission) {
-      // Create the user.
-      $account = $this->drupalCreateUser(
-        array(
-          'access content',
-          'edit any page content',
-          'delete any page content',
-          $permission,
-        )
-      );
-      $account->op = $op;
-      $accounts[] = $account;
-    }
-
-    $parameters = array(
-      'op' => array_keys($this->type_map),
-      'account' => $accounts,
-    );
-
-    // Test that the accounts have access to the correspoding page revision permissions.
-    $revision = $this->node_revisions['page'][1];
-
-    $permutations = $this->generatePermutations($parameters);
-    foreach ($permutations as $case) {
-      // Skip this test if there are no revisions for the node.
-      if (!($revision->isDefaultRevision() && (db_query('SELECT COUNT(vid) FROM {node_field_revision} WHERE nid = :nid', array(':nid' => $revision->nid))->fetchField() == 1 || $case['op'] == 'update' || $case['op'] == 'delete'))) {
-        if (!empty($case['account']->is_admin) || user_access($this->type_map[$case['op']], $case['account'])) {
-          $this->assertTrue(_node_revision_access($revision, $case['op'], $case['account']), "{$this->type_map[$case['op']]} granted.");
-        }
-        else {
-          $this->assertFalse(_node_revision_access($revision, $case['op'], $case['account']), "{$this->type_map[$case['op']]} not granted.");
-        }
-      }
-    }
-
-    // Test that the accounts have no access to the article revisions.
-    $revision = $this->node_revisions['article'][1];
-
-    foreach ($permutations as $case) {
-      $this->assertFalse(_node_revision_access($revision, $case['op'], $case['account']), "{$this->type_map[$case['op']]} did not grant revision permission for articles.");
-    }
-  }
-}
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsAllTestCase.php b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsAllTestCase.php
deleted file mode 100644
index f2209d7..0000000
--- a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsAllTestCase.php
+++ /dev/null
@@ -1,157 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\node\Tests\NodeRevisionsAllTestCase.
- */
-
-namespace Drupal\node\Tests;
-
-use Drupal\Core\Language\Language;
-
-/**
- * Tests actions against revisions for user with access to all revisions.
- */
-class NodeRevisionsAllTestCase extends NodeTestBase {
-  protected $nodes;
-  protected $logs;
-  protected $profile = "standard";
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Node revisions all',
-      'description' => 'Create a node with revisions and test viewing, saving, reverting, and deleting revisions for user with access to all.',
-      'group' => 'Node',
-    );
-  }
-
-  function setUp() {
-    parent::setUp();
-
-    // Create and log in user.
-    $web_user = $this->drupalCreateUser(
-      array(
-        'view page revisions',
-        'revert page revisions',
-        'delete page revisions',
-        'edit any page content',
-        'delete any page content'
-      )
-    );
-    $this->drupalLogin($web_user);
-
-    // Create an initial node.
-    $node = $this->drupalCreateNode();
-
-    $settings = get_object_vars($node);
-    $settings['revision'] = 1;
-
-    $nodes = array();
-    $logs = array();
-
-    // Get the original node.
-    $nodes[] = clone $node;
-
-    // Create three revisions.
-    $revision_count = 3;
-    for ($i = 0; $i < $revision_count; $i++) {
-      $logs[] = $node->log = $this->randomName(32);
-
-      // Create revision with a random title and body and update variables.
-      $node->title = $this->randomName();
-      $node->body[$node->language()->id][0] = array(
-        'value' => $this->randomName(32),
-        'format' => filter_default_format(),
-      );
-      $node->setNewRevision();
-      $node->save();
-
-      $node = node_load($node->nid, TRUE); // Make sure we get revision information.
-      $nodes[] = clone $node;
-    }
-
-    $this->nodes = $nodes;
-    $this->logs = $logs;
-  }
-
-  /**
-   * Checks node revision operations.
-   */
-  function testRevisions() {
-    $nodes = $this->nodes;
-    $logs = $this->logs;
-
-    // Get last node for simple checks.
-    $node = $nodes[3];
-
-    // Create and login user.
-    $content_admin = $this->drupalCreateUser(
-      array(
-        'view all revisions',
-        'revert all revisions',
-        'delete all revisions',
-        'edit any page content',
-        'delete any page content'
-      )
-    );
-    $this->drupalLogin($content_admin);
-
-    // Confirm the correct revision text appears on "view revisions" page.
-    $this->drupalGet("node/$node->nid/revisions/$node->vid/view");
-    $this->assertText($node->body[Language::LANGCODE_NOT_SPECIFIED][0]['value'], 'Correct text displays for version.');
-
-    // Confirm the correct log message appears on "revisions overview" page.
-    $this->drupalGet("node/$node->nid/revisions");
-    foreach ($logs as $log) {
-      $this->assertText($log, 'Log message found.');
-    }
-
-    // Confirm that this is the current revision.
-    $this->assertTrue($node->isDefaultRevision(), 'Third node revision is the current one.');
-
-    // Confirm that revisions revert properly.
-    $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/revert", array(), t('Revert'));
-    $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.',
-      array(
-        '@type' => 'Basic page',
-        '%title' => $nodes[1]->title,
-        '%revision-date' => format_date($nodes[1]->revision_timestamp)
-      )),
-      'Revision reverted.');
-    $reverted_node = node_load($node->nid, TRUE);
-    $this->assertTrue(($nodes[1]->body[Language::LANGCODE_NOT_SPECIFIED][0]['value'] == $reverted_node->body[Language::LANGCODE_NOT_SPECIFIED][0]['value']), 'Node reverted correctly.');
-
-    // Confirm that this is not the current version.
-    $node = node_revision_load($node->vid);
-    $this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the current one.');
-
-    // Confirm revisions delete properly.
-    $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/delete", array(), t('Delete'));
-    $this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.',
-      array(
-        '%revision-date' => format_date($nodes[1]->revision_timestamp),
-        '@type' => 'Basic page',
-        '%title' => $nodes[1]->title,
-      )),
-      'Revision deleted.');
-    $this->assertTrue(db_query('SELECT COUNT(vid) FROM {node_field_revision} WHERE nid = :nid and vid = :vid',
-      array(':nid' => $node->nid, ':vid' => $nodes[1]->vid))->fetchField() == 0,
-      'Revision not found.');
-
-    // Set the revision timestamp to an older date to make sure that the
-    // confirmation message correctly displays the stored revision date.
-    $old_revision_date = REQUEST_TIME - 86400;
-    db_update('node_field_revision')
-      ->condition('vid', $nodes[2]->vid)
-      ->fields(array(
-        'revision_timestamp' => $old_revision_date,
-      ))
-      ->execute();
-    $this->drupalPost("node/$node->nid/revisions/{$nodes[2]->vid}/revert", array(), t('Revert'));
-    $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.', array(
-      '@type' => 'Basic page',
-      '%title' => $nodes[2]->title,
-      '%revision-date' => format_date($old_revision_date),
-    )));
-  }
-}
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php
deleted file mode 100644
index dd2df8d..0000000
--- a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php
+++ /dev/null
@@ -1,206 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\node\Tests\NodeRevisionsTest.
- */
-
-namespace Drupal\node\Tests;
-
-use Drupal\Core\Language\Language;
-
-/**
- * Tests the node revision functionality.
- */
-class NodeRevisionsTest extends NodeTestBase {
-  protected $nodes;
-  protected $logs;
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Node revisions by type',
-      'description' => 'Create a node with revisions and test viewing, saving, reverting, and deleting revisions for users with access for this content type.',
-      'group' => 'Node',
-    );
-  }
-
-  function setUp() {
-    parent::setUp();
-
-    // Create and log in user.
-    $web_user = $this->drupalCreateUser(
-      array(
-        'view page revisions',
-        'revert page revisions',
-        'delete page revisions',
-        'edit any page content',
-        'delete any page content'
-      )
-    );
-
-    $this->drupalLogin($web_user);
-
-    // Create initial node.
-    $node = $this->drupalCreateNode();
-    $settings = get_object_vars($node);
-    $settings['revision'] = 1;
-    $settings['isDefaultRevision'] = TRUE;
-
-    $nodes = array();
-    $logs = array();
-
-    // Get original node.
-    $nodes[] = clone $node;
-
-    // Create three revisions.
-    $revision_count = 3;
-    for ($i = 0; $i < $revision_count; $i++) {
-      $logs[] = $node->log = $this->randomName(32);
-
-      // Create revision with a random title and body and update variables.
-      $node->title = $this->randomName();
-      $node->body[$node->language()->id][0] = array(
-        'value' => $this->randomName(32),
-        'format' => filter_default_format(),
-      );
-      $node->setNewRevision();
-      $node->save();
-
-      $node = node_load($node->nid); // Make sure we get revision information.
-      $nodes[] = clone $node;
-    }
-
-    $this->nodes = $nodes;
-    $this->logs = $logs;
-  }
-
-  /**
-   * Checks node revision related operations.
-   */
-  function testRevisions() {
-    $nodes = $this->nodes;
-    $logs = $this->logs;
-
-    // Get last node for simple checks.
-    $node = $nodes[3];
-
-    // Confirm the correct revision text appears on "view revisions" page.
-    $this->drupalGet("node/$node->nid/revisions/$node->vid/view");
-    $this->assertText($node->body[Language::LANGCODE_NOT_SPECIFIED][0]['value'], 'Correct text displays for version.');
-
-    // Confirm the correct log message appears on "revisions overview" page.
-    $this->drupalGet("node/$node->nid/revisions");
-    foreach ($logs as $log) {
-      $this->assertText($log, 'Log message found.');
-    }
-
-    // Confirm that this is the default revision.
-    $this->assertTrue($node->isDefaultRevision(), 'Third node revision is the default one.');
-
-    // Confirm that revisions revert properly.
-    $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/revert", array(), t('Revert'));
-    $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.',
-                        array('@type' => 'Basic page', '%title' => $nodes[1]->label(),
-                              '%revision-date' => format_date($nodes[1]->revision_timestamp))), 'Revision reverted.');
-    $reverted_node = node_load($node->nid, TRUE);
-    $this->assertTrue(($nodes[1]->body[Language::LANGCODE_NOT_SPECIFIED][0]['value'] == $reverted_node->body[Language::LANGCODE_NOT_SPECIFIED][0]['value']), 'Node reverted correctly.');
-
-    // Confirm that this is not the default version.
-    $node = node_revision_load($node->vid);
-    $this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the default one.');
-
-    // Confirm revisions delete properly.
-    $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/delete", array(), t('Delete'));
-    $this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.',
-                        array('%revision-date' => format_date($nodes[1]->revision_timestamp),
-                              '@type' => 'Basic page', '%title' => $nodes[1]->label())), 'Revision deleted.');
-    $this->assertTrue(db_query('SELECT COUNT(vid) FROM {node_field_revision} WHERE nid = :nid and vid = :vid', array(':nid' => $node->nid, ':vid' => $nodes[1]->vid))->fetchField() == 0, 'Revision not found.');
-
-    // Set the revision timestamp to an older date to make sure that the
-    // confirmation message correctly displays the stored revision date.
-    $old_revision_date = REQUEST_TIME - 86400;
-    db_update('node_field_revision')
-      ->condition('vid', $nodes[2]->vid)
-      ->fields(array(
-        'revision_timestamp' => $old_revision_date,
-      ))
-      ->execute();
-    $this->drupalPost("node/$node->nid/revisions/{$nodes[2]->vid}/revert", array(), t('Revert'));
-    $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.', array(
-      '@type' => 'Basic page',
-      '%title' => $nodes[2]->label(),
-      '%revision-date' => format_date($old_revision_date),
-    )));
-
-    // Make a new revision and set it to not be default.
-    // This will create a new revision that is not "front facing".
-    $new_node_revision = clone $node;
-    $new_body = $this->randomName();
-    $new_node_revision->body[Language::LANGCODE_NOT_SPECIFIED][0]['value'] = $new_body;
-    // Save this as a non-default revision.
-    $new_node_revision->setNewRevision();
-    $new_node_revision->isDefaultRevision = FALSE;
-    $new_node_revision->save();
-
-    $this->drupalGet("node/$node->nid");
-    $this->assertNoText($new_body, 'Revision body text is not present on default version of node.');
-
-    // Verify that the new body text is present on the revision.
-    $this->drupalGet("node/$node->nid/revisions/" . $new_node_revision->vid . "/view");
-    $this->assertText($new_body, 'Revision body text is present when loading specific revision.');
-
-    // Verify that the non-default revision vid is greater than the default
-    // revision vid.
-    $default_revision = db_select('node', 'n')
-      ->fields('n', array('vid'))
-      ->condition('nid', $node->nid)
-      ->execute()
-      ->fetchCol();
-    $default_revision_vid = $default_revision[0];
-    $this->assertTrue($new_node_revision->vid > $default_revision_vid, 'Revision vid is greater than default revision vid.');
-  }
-
-  /**
-   * Checks that revisions are correctly saved without log messages.
-   */
-  function testNodeRevisionWithoutLogMessage() {
-    // Create a node with an initial log message.
-    $log = $this->randomName(10);
-    $node = $this->drupalCreateNode(array('log' => $log));
-
-    // Save over the same revision and explicitly provide an empty log message
-    // (for example, to mimic the case of a node form submitted with no text in
-    // the "log message" field), and check that the original log message is
-    // preserved.
-    $new_title = $this->randomName(10) . 'testNodeRevisionWithoutLogMessage1';
-
-    $node = clone $node;
-    $node->title = $new_title;
-    $node->log = '';
-    $node->setNewRevision(FALSE);
-
-    $node->save();
-    $this->drupalGet('node/' . $node->nid);
-    $this->assertText($new_title, 'New node title appears on the page.');
-    $node_revision = node_load($node->nid, TRUE);
-    $this->assertEqual($node_revision->log, $log, 'After an existing node revision is re-saved without a log message, the original log message is preserved.');
-
-    // Create another node with an initial log message.
-    $node = $this->drupalCreateNode(array('log' => $log));
-
-    // Save a new node revision without providing a log message, and check that
-    // this revision has an empty log message.
-    $new_title = $this->randomName(10) . 'testNodeRevisionWithoutLogMessage2';
-
-    $node = clone $node;
-    $node->title = $new_title;
-    $node->setNewRevision();
-    $node->log = NULL;
-
-    $node->save();
-    $this->drupalGet('node/' . $node->nid);
-    $this->assertText($new_title, 'New node title appears on the page.');
-    $node_revision = node_load($node->nid, TRUE);
-    $this->assertTrue(empty($node_revision->log), 'After a new node revision is saved with an empty log message, the log message for the node is empty.');
-  }
-}
diff --git a/core/modules/node/lib/Drupal/node/Tests/PageEditTest.php b/core/modules/node/lib/Drupal/node/Tests/PageEditTest.php
index 2407dfb..bfaf617 100644
--- a/core/modules/node/lib/Drupal/node/Tests/PageEditTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/PageEditTest.php
@@ -73,29 +73,6 @@ function testPageEdit() {
     // Check that the title and body fields are displayed with the updated values.
     $this->assertText($edit[$title_key], 'Title displayed.');
     $this->assertText($edit[$body_key], 'Body displayed.');
-
-    // Login as a second administrator user.
-    $second_web_user = $this->drupalCreateUser(array('administer nodes', 'edit any page content'));
-    $this->drupalLogin($second_web_user);
-    // Edit the same node, creating a new revision.
-    $this->drupalGet("node/$node->nid/edit");
-    $edit = array();
-    $edit['title'] = $this->randomName(8);
-    $edit[$body_key] = $this->randomName(16);
-    $edit['revision'] = TRUE;
-    $this->drupalPost(NULL, $edit, t('Save and keep published'));
-
-    // Ensure that the node revision has been created.
-    $revised_node = $this->drupalGetNodeByTitle($edit['title'], TRUE);
-    $this->assertNotIdentical($node->vid, $revised_node->vid, 'A new revision has been created.');
-    // Ensure that the node author is preserved when it was not changed in the
-    // edit form.
-    $this->assertIdentical($node->uid, $revised_node->uid, 'The node author has been preserved.');
-    // Ensure that the revision authors are different since the revisions were
-    // made by different users.
-    $first_node_version = node_revision_load($node->vid);
-    $second_node_version = node_revision_load($revised_node->vid);
-    $this->assertNotIdentical($first_node_version->revision_uid, $second_node_version->revision_uid, 'Each revision has a distinct user.');
   }
 
   /**
diff --git a/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php b/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
index b485545..507492b 100644
--- a/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
@@ -177,38 +177,4 @@ function testPagePreview() {
     $this->drupalPost('node/add/page', $edit, t('Save'));
   }
 
-  /**
-   * Checks the node preview functionality, when using revisions.
-   */
-  function testPagePreviewWithRevisions() {
-    $langcode = Language::LANGCODE_NOT_SPECIFIED;
-    $title_key = "title";
-    $body_key = "body[$langcode][0][value]";
-    $term_key = "{$this->field_name}[$langcode]";
-    // Force revision on "Basic page" content.
-    $this->container->get('config.factory')->get('node.type.page')->set('settings.node.options', array('status', 'revision'))->save();
-
-    // Fill in node creation form and preview node.
-    $edit = array();
-    $edit[$title_key] = $this->randomName(8);
-    $edit[$body_key] = $this->randomName(16);
-    $edit[$term_key] = $this->term->id();
-    $edit['log'] = $this->randomName(32);
-    $this->drupalPost('node/add/page', $edit, t('Preview'));
-
-    // Check that the preview is displaying the title, body and term.
-    $this->assertTitle(t('Preview | Drupal'), 'Basic page title is preview.');
-    $this->assertText($edit[$title_key], 'Title displayed.');
-    $this->assertText($edit[$body_key], 'Body displayed.');
-    $this->assertText($edit[$term_key], 'Term displayed.');
-
-    // Check that the title, body and term fields are displayed with the correct values.
-    $this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.');
-    $this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.');
-    $this->assertFieldByName($term_key, $edit[$term_key], 'Term field displayed.');
-
-    // Check that the log field has the correct value.
-    $this->assertFieldByName('log', $edit['log'], 'Log field displayed.');
-  }
-
 }
diff --git a/core/modules/node/node.js b/core/modules/node/node.js
index b61c117..2d71321 100644
--- a/core/modules/node/node.js
+++ b/core/modules/node/node.js
@@ -10,21 +10,6 @@
 Drupal.behaviors.nodeDetailsSummaries = {
   attach: function (context) {
     var $context = $(context);
-    $context.find('.node-form-revision-information').drupalSetSummary(function (context) {
-      var $context = $(context);
-      var revisionCheckbox = $context.find('.form-item-revision input');
-
-      // Return 'New revision' if the 'Create new revision' checkbox is checked,
-      // or if the checkbox doesn't exist, but the revision log does. For users
-      // without the "Administer content" permission the checkbox won't appear,
-      // but the revision log will if the content type is set to auto-revision.
-      if (revisionCheckbox.is(':checked') || (!revisionCheckbox.length && $context.find('.form-item-log textarea').length)) {
-        return Drupal.t('New revision');
-      }
-
-      return Drupal.t('No revision');
-    });
-
     $context.find('.node-form-author').drupalSetSummary(function (context) {
       var $context = $(context);
       var name = $context.find('.form-item-name input').val() || Drupal.settings.anonymous,
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 45f19c7..f18b87d 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -109,9 +109,6 @@ function node_help($path, $arg) {
       $output .= '<dd>' . t('The Node module gives users with the <em>Administer content types</em> permission the ability to <a href="@content-new">create new content types</a> in addition to the default ones already configured. Creating custom content types allows you the flexibility to add <a href="@field">fields</a> and configure default settings that suit the differing needs of various site content.', array('@content-new' => url('admin/structure/types/add'), '@field' => url('admin/help/field'))) . '</dd>';
       $output .= '<dt>' . t('Administering content') . '</dt>';
       $output .= '<dd>' . t('The <a href="@content">Content administration page</a> allows you to review and bulk manage your site content.', array('@content' => url('admin/content'))) . '</dd>';
-      $output .= '<dt>' . t('Creating revisions') . '</dt>';
-      $output .= '<dd>' . t('The Node module also enables you to create multiple versions of any content, and revert to older versions using the <em>Revision information</em> settings.') . '</dd>';
-      $output .= '<dt>' . t('User permissions') . '</dt>';
       $output .= '<dd>' . t('The Node module makes a number of permissions available for each content type, which can be set by role on the <a href="@permissions">permissions page</a>.', array('@permissions' => url('admin/people/permissions', array('fragment' => 'module-node')))) . '</dd>';
       $output .= '</dl>';
       return $output;
@@ -128,9 +125,6 @@ function node_help($path, $arg) {
       return '<p>' . t('Content items can be displayed using different view modes: Teaser, Full content, Print, RSS, etc. <em>Teaser</em> is a short format that is typically used in lists of multiple content items. <em>Full content</em> is typically used when the content is displayed on its own page.') . '</p>' .
         '<p>' . t('Here, you can define which fields are shown and hidden when %type content is displayed in each view mode, and define how the fields are displayed in each view mode.', array('%type' => $type->label())) . '</p>';
 
-    case 'node/%/revisions':
-      return '<p>' . t('Revisions allow you to track differences between multiple versions of your content, and revert back to older versions.') . '</p>';
-
     case 'node/%/edit':
       $node = node_load($arg[1]);
       $type = node_type_load($node->bundle());
@@ -227,9 +221,6 @@ function node_admin_paths() {
     $paths = array(
       'node/*/edit' => TRUE,
       'node/*/delete' => TRUE,
-      'node/*/revisions' => TRUE,
-      'node/*/revisions/*/revert' => TRUE,
-      'node/*/revisions/*/delete' => TRUE,
       'node/*/translations' => TRUE,
       'node/*/translations/*' => TRUE,
       'node/add' => TRUE,
@@ -546,19 +537,6 @@ function node_load($nid = NULL, $reset = FALSE) {
 }
 
 /**
- * Loads a node revision from the database.
- *
- * @param int $nid
- *   The node revision id.
- *
- * @return \Drupal\node\Node|null
- *   A fully-populated node entity or NULL if the node is not found.
- */
-function node_revision_load($vid = NULL) {
-  return entity_revision_load('node', $vid);
-}
-
-/**
  * Prepares a node for saving by populating the author and creation date.
  *
  * @param \Drupal\Core\Entity\EntityInterface $node
@@ -581,12 +559,6 @@ function node_submit(EntityInterface $node) {
     }
   }
 
-  // If a new revision is created, save the current user as revision author.
-  if ($node->isNewRevision()) {
-    $node->setRevisionAuthorId($user->id());
-    $node->setRevisionCreationTime(REQUEST_TIME);
-  }
-
   $node->setCreatedTime(!empty($node->date) && $node->date instanceOf DrupalDateTime ? $node->date->getTimestamp() : REQUEST_TIME);
   $node->validated = TRUE;
 
@@ -594,19 +566,6 @@ function node_submit(EntityInterface $node) {
 }
 
 /**
- * Deletes a node revision.
- *
- * @param $revision_id
- *   The revision ID to delete.
- *
- * @return
- *   TRUE if the revision deletion was successful; otherwise, FALSE.
- */
-function node_revision_delete($revision_id) {
-  entity_revision_delete('node', $revision_id);
-}
-
-/**
  * Page callback: Generates an array which displays a node detail page.
  *
  * @param \Drupal\Core\Entity\EntityInterface $node
@@ -793,17 +752,6 @@ function node_permission() {
     'view own unpublished content' => array(
       'title' => t('View own unpublished content'),
     ),
-    'view all revisions' => array(
-      'title' => t('View all revisions'),
-    ),
-    'revert all revisions' => array(
-      'title' => t('Revert all revisions'),
-      'description' => t('Role requires permission <em>view revisions</em> and <em>edit rights</em> for nodes in question, or <em>administer nodes</em>.'),
-    ),
-    'delete all revisions' => array(
-      'title' => t('Delete all revisions'),
-      'description' => t('Role requires permission to <em>view revisions</em> and <em>delete rights</em> for nodes in question, or <em>administer nodes</em>.'),
-    ),
   );
 
   // Generate standard node permissions for all applicable node types.
@@ -1031,11 +979,6 @@ function node_user_cancel($edit, $account, $method) {
         ->execute()
         ->fetchCol();
       node_mass_update($nodes, array('uid' => 0), NULL, TRUE);
-      // Anonymize old revisions.
-      db_update('node_field_revision')
-        ->fields(array('uid' => 0))
-        ->condition('uid', $account->id())
-        ->execute();
       break;
   }
 }
@@ -1053,11 +996,6 @@ function node_user_predelete($account) {
     ->execute()
     ->fetchCol();
   entity_delete_multiple('node', $nodes);
-  // Delete old revisions.
-  $revisions = db_query('SELECT DISTINCT vid FROM {node_field_revision} WHERE uid = :uid', array(':uid' => $account->id()))->fetchCol();
-  foreach ($revisions as $revision) {
-    node_revision_delete($revision);
-  }
 }
 
 /**
@@ -1095,31 +1033,6 @@ function theme_node_search_admin($variables) {
 }
 
 /**
- * Access callback: Checks node revision access.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   The node to check.
- * @param $op
- *   (optional) The specific operation being checked. Defaults to 'view.'
- * @param object $account
- *   (optional) A user object representing the user for whom the operation is
- *   to be performed. Determines access for a user other than the current user.
- *   Defaults to NULL.
- * @param $langcode
- *   (optional) Language code for the variant of the node. Different language
- *   variants might have different permissions associated. If NULL, the
- *   original langcode of the node is used. Defaults to NULL.
- *
- * @return
- *   TRUE if the operation may be performed, FALSE otherwise.
- *
- * @see node_menu()
- */
-function _node_revision_access(EntityInterface $node, $op = 'view', $account = NULL, $langcode = NULL) {
-  return Drupal::service('access_check.node.revision')->checkAccess($node, $op, $account, $langcode);
-}
-
-/**
  * Access callback: Checks whether the user has permission to add a node.
  *
  * @return
@@ -1232,31 +1145,6 @@ function node_menu() {
     'type' => MENU_LOCAL_TASK,
     'context' => MENU_CONTEXT_INLINE,
   );
-  $items['node/%node/revisions'] = array(
-    'title' => 'Revisions',
-    'page callback' => 'node_revision_overview',
-    'page arguments' => array(1),
-    'access callback' => '_node_revision_access',
-    'access arguments' => array(1),
-    'weight' => 20,
-    'type' => MENU_LOCAL_TASK,
-    'file' => 'node.pages.inc',
-  );
-  $items['node/%node/revisions/%node_revision/view'] = array(
-    'title' => 'Revisions',
-    'page callback' => 'node_show',
-    'page arguments' => array(3, TRUE),
-    'access callback' => '_node_revision_access',
-    'access arguments' => array(3),
-  );
-  $items['node/%node/revisions/%node_revision/revert'] = array(
-    'title' => 'Revert to earlier revision',
-    'route_name' => 'node_revision_revert_confirm',
-  );
-  $items['node/%node/revisions/%node_revision/delete'] = array(
-    'title' => 'Delete earlier revision',
-    'route_name' => 'node_revision_delete_confirm',
-  );
   return $items;
 }
 
@@ -1310,25 +1198,6 @@ function node_last_changed($nid, $langcode = NULL) {
 }
 
 /**
- * Returns a list of all the existing revision numbers for the node passed in.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   The node entity.
- *
- * @return
- *   An associative array keyed by node revision number.
- */
-function node_revision_list(EntityInterface $node) {
-  $revisions = array();
-  $result = db_query('SELECT nfr.vid, nfr.title, nfr.log, nfr.revision_uid AS uid, n.vid AS current_vid, nfr.revision_timestamp, u.name FROM {node_field_revision} nfr LEFT JOIN {node} n ON n.vid = nfr.vid INNER JOIN {users} u ON u.uid = nfr.revision_uid WHERE nfr.nid = :nid AND nfr.default_langcode = 1 ORDER BY nfr.vid DESC', array(':nid' => $node->id()));
-  foreach ($result as $revision) {
-    $revisions[$revision->vid] = $revision;
-  }
-
-  return $revisions;
-}
-
-/**
  * Finds the most recently changed nodes that are available to the current user.
  *
  * @param $number
@@ -2117,17 +1986,6 @@ function node_list_permissions($type) {
     "delete any $type->type content" => array(
       'title' => t('%type_name: Delete any content', array('%type_name' => $type->name)),
     ),
-    "view $type->type revisions" => array(
-      'title' => t('%type_name: View revisions', array('%type_name' => $type->name)),
-    ),
-    "revert $type->type revisions" => array(
-      'title' => t('%type_name: Revert revisions', array('%type_name' => $type->name)),
-      'description' => t('Role requires permission <em>view revisions</em> and <em>edit rights</em> for nodes in question, or <em>administer nodes</em>.'),
-    ),
-    "delete $type->type revisions" => array(
-      'title' => t('%type_name: Delete revisions', array('%type_name' => $type->name)),
-      'description' => t('Role requires permission to <em>view revisions</em> and <em>delete rights</em> for nodes in question, or <em>administer nodes</em>.'),
-    ),
   );
   return $perms;
 }
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index 7dff75d..b7bbbd8 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Callbacks for adding, editing, and deleting content and managing revisions.
+ * Callbacks for adding, editing, and deleting content.
  *
  * Also includes validation, submission and other helper functions.
  *
@@ -179,86 +179,3 @@ function theme_node_preview($variables) {
 
   return $output;
 }
-
-/**
- * Page callback: Generates an overview table of older revisions of a node.
- *
- * @param object $node
- *   A node object.
- *
- * @return array
- *   An array as expected by drupal_render().
- *
- * @see node_menu()
- */
-function node_revision_overview($node) {
-  drupal_set_title(t('Revisions for %title', array('%title' => $node->label())), PASS_THROUGH);
-
-  $header = array(t('Revision'), t('Operations'));
-
-  $revisions = node_revision_list($node);
-
-  $rows = array();
-  $type = $node->type;
-
-  $revert_permission = FALSE;
-  if ((user_access("revert $type revisions") || user_access('revert all revisions') || user_access('administer nodes')) && node_access('update', $node)) {
-    $revert_permission = TRUE;
-  }
-  $delete_permission = FALSE;
-  if ((user_access("delete $type revisions") || user_access('delete all revisions') || user_access('administer nodes')) && node_access('delete', $node)) {
-    $delete_permission = TRUE;
-  }
-  foreach ($revisions as $revision) {
-    $row = array();
-    $type = $node->type;
-    if ($revision->current_vid > 0) {
-      $username = array(
-        '#theme' => 'username',
-        '#account' => user_load($revision->uid),
-      );
-      $row[] = array('data' => t('!date by !username', array('!date' => l(format_date($revision->revision_timestamp, 'short'), "node/$node->nid"), '!username' => drupal_render($username)))
-                               . (($revision->log != '') ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : ''),
-                     'class' => array('revision-current'));
-      $row[] = array('data' => drupal_placeholder(t('current revision')), 'class' => array('revision-current'));
-    }
-    else {
-      $username = array(
-        '#theme' => 'username',
-        '#account' => user_load($revision->uid),
-      );
-      $row[] = t('!date by !username', array('!date' => l(format_date($revision->revision_timestamp, 'short'), "node/$node->nid/revisions/$revision->vid/view"), '!username' => drupal_render($username)))
-               . (($revision->log != '') ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : '');
-      if ($revert_permission) {
-        $links['revert'] = array(
-          'title' => t('Revert'),
-          'href' => "node/$node->nid/revisions/$revision->vid/revert",
-        );
-      }
-      if ($delete_permission) {
-        $links['delete'] = array(
-          'title' => t('Delete'),
-          'href' => "node/$node->nid/revisions/$revision->vid/delete",
-        );
-      }
-      $row[] = array(
-        'data' => array(
-          '#type' => 'operations',
-          '#links' => $links,
-        ),
-      );
-    }
-    $rows[] = $row;
-  }
-
-  $build['node_revisions_table'] = array(
-    '#theme' => 'table',
-    '#rows' => $rows,
-    '#header' => $header,
-    '#attached' => array (
-      'css' => array(drupal_get_path('module', 'node') . '/css/node.admin.css'),
-    ),
-  );
-
-  return $build;
-}
diff --git a/core/modules/node/node.routing.yml b/core/modules/node/node.routing.yml
index dfdc0a6..75f48b1 100644
--- a/core/modules/node/node.routing.yml
+++ b/core/modules/node/node.routing.yml
@@ -19,20 +19,6 @@ node_delete_confirm:
   requirements:
     _entity_access: 'node.delete'
 
-node_revision_revert_confirm:
-  pattern: '/node/{node}/revisions/{node_revision}/revert'
-  defaults:
-    _form: '\Drupal\node\Form\NodeRevisionRevertForm'
-  requirements:
-    _access_node_revision: 'update'
-
-node_revision_delete_confirm:
-  pattern: '/node/{node}/revisions/{node_revision}/delete'
-  defaults:
-    _form: '\Drupal\node\Form\NodeRevisionDeleteForm'
-  requirements:
-    _access_node_revision: 'delete'
-
 node_overview_types:
   pattern: '/admin/structure/types'
   defaults:
diff --git a/core/modules/node/node.services.yml b/core/modules/node/node.services.yml
index ab49617..6f486f7 100644
--- a/core/modules/node/node.services.yml
+++ b/core/modules/node/node.services.yml
@@ -2,8 +2,3 @@ services:
   node.grant_storage:
     class: Drupal\node\NodeGrantDatabaseStorage
     arguments: ['@database', '@module_handler']
-  access_check.node.revision:
-    class: Drupal\node\Access\NodeRevisionAccessCheck
-    arguments: ['@plugin.manager.entity', '@database']
-    tags:
-      - { name: access_check }
diff --git a/core/modules/node_revision/css/node_revision.css b/core/modules/node_revision/css/node_revision.css
new file mode 100644
index 0000000..101a38d
--- /dev/null
+++ b/core/modules/node_revision/css/node_revision.css
@@ -0,0 +1,11 @@
+/**
+ * @file
+ * Styles for administration pages.
+ */
+
+/**
+ * Revisions overview screen.
+ */
+.revision-current {
+  background: #ffc;
+}
diff --git a/core/modules/node_revision/lib/Drupal/node_revision/Access/NodeRevisionAccessCheck.php b/core/modules/node_revision/lib/Drupal/node_revision/Access/NodeRevisionAccessCheck.php
new file mode 100644
index 0000000..8d490f1
--- /dev/null
+++ b/core/modules/node_revision/lib/Drupal/node_revision/Access/NodeRevisionAccessCheck.php
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Access\NodeRevisionAccessCheck.
+ */
+
+namespace Drupal\node_revision\Access;
+
+use Drupal\Core\Access\AccessCheckInterface;
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Entity\EntityManager;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\node\NodeInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Provides an access checker for node revisions.
+ */
+class NodeRevisionAccessCheck implements AccessCheckInterface {
+
+  /**
+   * The node storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
+   */
+  protected $nodeStorage;
+
+  /**
+   * The node access controller.
+   *
+   * @var \Drupal\Core\Entity\EntityAccessControllerInterface
+   */
+  protected $nodeAccess;
+
+  /**
+   * The database connection.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $connection;
+
+  /**
+   * A static cache of access checks.
+   *
+   * @var array
+   */
+  protected $access = array();
+
+  /**
+   * Constructs a new NodeRevisionAccessCheck.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager.
+   * @param \Drupal\Core\Database\Connection $connection
+   *   The database connection.
+   */
+  public function __construct(EntityManager $entity_manager, Connection $connection) {
+    $this->nodeStorage = $entity_manager->getStorageController('node');
+    $this->nodeAccess = $entity_manager->getAccessController('node');
+    $this->connection = $connection;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applies(Route $route) {
+    return array_key_exists('_access_node_revision', $route->getRequirements());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access(Route $route, Request $request) {
+    $revision = $this->nodeStorage->loadRevision($request->attributes->get('node_revision'));
+    return $this->checkAccess($revision, $route->getRequirement('_access_node_revision')) ? static::ALLOW : static::DENY;
+  }
+
+  /**
+   * Checks node revision access.
+   *
+   * @param \Drupal\node\NodeInterface $node
+   *   The node to check.
+   * @param string $op
+   *   (optional) The specific operation being checked. Defaults to 'view.'
+   * @param \Drupal\Core\Session\AccountInterface|null $account
+   *   (optional) A user object representing the user for whom the operation is
+   *   to be performed. Determines access for a user other than the current user.
+   *   Defaults to NULL.
+   * @param string|null $langcode
+   *   (optional) Language code for the variant of the node. Different language
+   *   variants might have different permissions associated. If NULL, the
+   *   original langcode of the node is used. Defaults to NULL.
+   *
+   * @return bool
+   *   TRUE if the operation may be performed, FALSE otherwise.
+   */
+  public function checkAccess(NodeInterface $node, $op = 'view', AccountInterface $account = NULL, $langcode = NULL) {
+    $map = array(
+      'view' => 'view all revisions',
+      'update' => 'revert all revisions',
+      'delete' => 'delete all revisions',
+    );
+    $bundle = $node->bundle();
+    $type_map = array(
+      'view' => "view $bundle revisions",
+      'update' => "revert $bundle revisions",
+      'delete' => "delete $bundle revisions",
+    );
+
+    if (!$node || !isset($map[$op]) || !isset($type_map[$op])) {
+      // If there was no node to check against, or the $op was not one of the
+      // supported ones, we return access denied.
+      return FALSE;
+    }
+
+    if (!isset($account)) {
+      $account = $GLOBALS['user'];
+    }
+
+    // If no language code was provided, default to the node revision's langcode.
+    if (empty($langcode)) {
+      $langcode = $node->language()->id;
+    }
+
+    // Statically cache access by revision ID, language code, user account ID,
+    // and operation.
+    $cid = $node->getRevisionId() . ':' . $langcode . ':' . $account->id() . ':' . $op;
+
+    if (!isset($this->access[$cid])) {
+      // Perform basic permission checks first.
+      if (!user_access($map[$op], $account) && !user_access($type_map[$op], $account) && !user_access('administer nodes', $account)) {
+        return $this->access[$cid] = FALSE;
+      }
+
+      // There should be at least two revisions. If the vid of the given node
+      // and the vid of the default revision differ, then we already have two
+      // different revisions so there is no need for a separate database check.
+      // Also, if you try to revert to or delete the default revision, that's
+      // not good.
+      if ($node->isDefaultRevision() && ($this->connection->query('SELECT COUNT(*) FROM {node_field_revision} WHERE nid = :nid AND default_langcode = 1', array(':nid' => $node->id()))->fetchField() == 1 || $op == 'update' || $op == 'delete')) {
+        $this->access[$cid] = FALSE;
+      }
+      elseif (user_access('administer nodes', $account)) {
+        $this->access[$cid] = TRUE;
+      }
+      else {
+        // First check the access to the default revision and finally, if the
+        // node passed in is not the default revision then access to that, too.
+        $this->access[$cid] = $this->nodeAccess->access($this->nodeStorage->load($node->id()), $op, $langcode, $account) && ($node->isDefaultRevision() || $this->nodeAccess->access($node, $op, $langcode, $account));
+      }
+    }
+
+    return $this->access[$cid];
+  }
+
+}
diff --git a/core/modules/node_revision/lib/Drupal/node_revision/Form/NodeRevisionDeleteForm.php b/core/modules/node_revision/lib/Drupal/node_revision/Form/NodeRevisionDeleteForm.php
new file mode 100644
index 0000000..30d1a6c
--- /dev/null
+++ b/core/modules/node_revision/lib/Drupal/node_revision/Form/NodeRevisionDeleteForm.php
@@ -0,0 +1,130 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node_revision\Form\NodeRevisionDeleteForm.
+ */
+
+namespace Drupal\node_revision\Form;
+
+use Drupal\Core\Controller\ControllerInterface;
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\node\NodeInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Provides a form for reverting a node revision.
+ */
+class NodeRevisionDeleteForm extends ConfirmFormBase implements ControllerInterface {
+
+  /**
+   * The node revision.
+   *
+   * @var \Drupal\node\NodeInterface
+   */
+  protected $revision;
+
+  /**
+   * The node storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
+   */
+  protected $nodeStorage;
+
+  /**
+   * The node type storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
+   */
+  protected $nodeTypeStorage;
+
+  /**
+   * The database connection.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $connection;
+
+  /**
+   * Constructs a new NodeRevisionDeleteForm.
+   *
+   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $node_storage
+   *   The node storage.
+   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $node_type_storage
+   *   The node type storage.
+   * @param \Drupal\Core\Database\Connection $connection
+   *   The database connection.
+   */
+  public function __construct(EntityStorageControllerInterface $node_storage, EntityStorageControllerInterface $node_type_storage, Connection $connection) {
+    $this->nodeStorage = $node_storage;
+    $this->nodeTypeStorage = $node_type_storage;
+    $this->connection = $connection;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    $entity_manager = $container->get('plugin.manager.entity');
+    return new static(
+      $entity_manager->getStorageController('node'),
+      $entity_manager->getStorageController('node_type'),
+      $container->get('database')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormID() {
+    return 'node_revision_delete_confirm';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    return t('Are you sure you want to delete the revision from %revision-date?', array('%revision-date' => format_date($this->revision->getRevisionCreationTime())));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelPath() {
+    return 'node/' . $this->revision->id() . '/revisions';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfirmText() {
+    return t('Delete');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state, Request $request = NULL, $node_revision = NULL) {
+    $this->revision = $this->nodeStorage->loadRevision($node_revision);
+    return parent::buildForm($form, $form_state, $request);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    $this->nodeStorage->deleteRevision($this->revision->getRevisionId());
+
+    watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $this->revision->bundle(), '%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()));
+    $node_type = $this->nodeTypeStorage->load($this->revision->bundle())->label();
+    drupal_set_message(t('Revision from %revision-date of @type %title has been deleted.', array('%revision-date' => format_date($this->revision->getRevisionCreationTime()), '@type' => $node_type, '%title' => $this->revision->label())));
+    $form_state['redirect'] = 'node/' . $this->revision->id();
+    if ($this->connection->query('SELECT COUNT(DISTINCT vid) FROM {node_field_revision} WHERE nid = :nid', array(':nid' => $this->revision->id()))->fetchField() > 1) {
+      $form_state['redirect'] .= '/revisions';
+    }
+  }
+
+}
diff --git a/core/modules/node_revision/lib/Drupal/node_revision/Form/NodeRevisionRevertForm.php b/core/modules/node_revision/lib/Drupal/node_revision/Form/NodeRevisionRevertForm.php
new file mode 100644
index 0000000..90db54c
--- /dev/null
+++ b/core/modules/node_revision/lib/Drupal/node_revision/Form/NodeRevisionRevertForm.php
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node_revision\Form\NodeRevisionDeleteForm.
+ */
+
+namespace Drupal\node_revision\Form;
+
+use Drupal\Core\Controller\ControllerInterface;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\node\NodeInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Provides a form for reverting a node revision.
+ */
+class NodeRevisionRevertForm extends ConfirmFormBase implements ControllerInterface {
+
+  /**
+   * The node revision.
+   *
+   * @var \Drupal\node\NodeInterface
+   */
+  protected $revision;
+
+  /**
+   * The node storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
+   */
+  protected $nodeStorage;
+
+  /**
+   * Constructs a new NodeRevisionRevertForm.
+   *
+   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $node_storage
+   *   The node storage.
+   */
+  public function __construct(EntityStorageControllerInterface $node_storage) {
+    $this->nodeStorage = $node_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.entity')->getStorageController('node')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormID() {
+    return 'node_revision_revert_confirm';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    return t('Are you sure you want to revert to the revision from %revision-date?', array('%revision-date' => format_date($this->revision->getRevisionCreationTime())));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelPath() {
+    return 'node/' . $this->revision->id() . '/revisions';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfirmText() {
+    return t('Revert');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state, Request $request = NULL, $node_revision = NULL) {
+    $this->revision = $this->nodeStorage->loadRevision($node_revision);
+    return parent::buildForm($form, $form_state, $request);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    $this->revision->setNewRevision();
+    // Make this the new default revision for the node.
+    $this->revision->isDefaultRevision(TRUE);
+
+    // The revision timestamp will be updated when the revision is saved. Keep the
+    // original one for the confirmation message.
+    $original_revision_timestamp = $this->revision->getRevisionCreationTime();
+
+    $this->revision->log = t('Copy of the revision from %date.', array('%date' => format_date($original_revision_timestamp)));
+
+    $this->revision->save();
+
+    watchdog('content', '@type: reverted %title revision %revision.', array('@type' => $this->revision->bundle(), '%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()));
+    drupal_set_message(t('@type %title has been reverted back to the revision from %revision-date.', array('@type' => node_get_type_label($this->revision), '%title' => $this->revision->label(), '%revision-date' => format_date($original_revision_timestamp))));
+    $form_state['redirect'] = 'node/' . $this->revision->id() . '/revisions';
+  }
+
+}
diff --git a/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionAllTestCase.php b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionAllTestCase.php
new file mode 100644
index 0000000..146ba51
--- /dev/null
+++ b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionAllTestCase.php
@@ -0,0 +1,157 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\node_revision\Tests\NodeRevisionAllTestCase.
+ */
+
+namespace Drupal\node_revision\Tests;
+
+use Drupal\Core\Language\Language;
+
+/**
+ * Tests actions against revisions for user with access to all revisions.
+ */
+class NodeRevisionAllTestCase extends NodeRevisionTestBase {
+  protected $nodes;
+  protected $logs;
+  protected $profile = "standard";
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node revisions all',
+      'description' => 'Create a node with revisions and test viewing, saving, reverting, and deleting revisions for user with access to all.',
+      'group' => 'Node Revisioning',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+
+    // Create and log in user.
+    $web_user = $this->drupalCreateUser(
+      array(
+        'view page revisions',
+        'revert page revisions',
+        'delete page revisions',
+        'edit any page content',
+        'delete any page content'
+      )
+    );
+    $this->drupalLogin($web_user);
+
+    // Create an initial node.
+    $node = $this->drupalCreateNode();
+
+    $settings = get_object_vars($node);
+    $settings['revision'] = 1;
+
+    $nodes = array();
+    $logs = array();
+
+    // Get the original node.
+    $nodes[] = clone $node;
+
+    // Create three revisions.
+    $revision_count = 3;
+    for ($i = 0; $i < $revision_count; $i++) {
+      $logs[] = $node->log = $this->randomName(32);
+
+      // Create revision with a random title and body and update variables.
+      $node->title = $this->randomName();
+      $node->body[$node->language()->id][0] = array(
+        'value' => $this->randomName(32),
+        'format' => filter_default_format(),
+      );
+      $node->setNewRevision();
+      $node->save();
+
+      $node = node_load($node->nid, TRUE); // Make sure we get revision information.
+      $nodes[] = clone $node;
+    }
+
+    $this->nodes = $nodes;
+    $this->logs = $logs;
+  }
+
+  /**
+   * Checks node revision operations.
+   */
+  function testRevisions() {
+    $nodes = $this->nodes;
+    $logs = $this->logs;
+
+    // Get last node for simple checks.
+    $node = $nodes[3];
+
+    // Create and login user.
+    $content_admin = $this->drupalCreateUser(
+      array(
+        'view all revisions',
+        'revert all revisions',
+        'delete all revisions',
+        'edit any page content',
+        'delete any page content'
+      )
+    );
+    $this->drupalLogin($content_admin);
+
+    // Confirm the correct revision text appears on "view revisions" page.
+    $this->drupalGet("node/$node->nid/revisions/$node->vid/view");
+    $this->assertText($node->body[Language::LANGCODE_NOT_SPECIFIED][0]['value'], 'Correct text displays for version.');
+
+    // Confirm the correct log message appears on "revisions overview" page.
+    $this->drupalGet("node/$node->nid/revisions");
+    foreach ($logs as $log) {
+      $this->assertText($log, 'Log message found.');
+    }
+
+    // Confirm that this is the current revision.
+    $this->assertTrue($node->isDefaultRevision(), 'Third node revision is the current one.');
+
+    // Confirm that revisions revert properly.
+    $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/revert", array(), t('Revert'));
+    $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.',
+      array(
+        '@type' => 'Basic page',
+        '%title' => $nodes[1]->title,
+        '%revision-date' => format_date($nodes[1]->revision_timestamp)
+      )),
+      'Revision reverted.');
+    $reverted_node = node_load($node->nid, TRUE);
+    $this->assertTrue(($nodes[1]->body[Language::LANGCODE_NOT_SPECIFIED][0]['value'] == $reverted_node->body[Language::LANGCODE_NOT_SPECIFIED][0]['value']), 'Node reverted correctly.');
+
+    // Confirm that this is not the current version.
+    $node = node_revision_load($node->vid);
+    $this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the current one.');
+
+    // Confirm revisions delete properly.
+    $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/delete", array(), t('Delete'));
+    $this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.',
+      array(
+        '%revision-date' => format_date($nodes[1]->revision_timestamp),
+        '@type' => 'Basic page',
+        '%title' => $nodes[1]->title,
+      )),
+      'Revision deleted.');
+    $this->assertTrue(db_query('SELECT COUNT(vid) FROM {node_field_revision} WHERE nid = :nid and vid = :vid',
+      array(':nid' => $node->nid, ':vid' => $nodes[1]->vid))->fetchField() == 0,
+      'Revision not found.');
+
+    // Set the revision timestamp to an older date to make sure that the
+    // confirmation message correctly displays the stored revision date.
+    $old_revision_date = REQUEST_TIME - 86400;
+    db_update('node_field_revision')
+      ->condition('vid', $nodes[2]->vid)
+      ->fields(array(
+        'revision_timestamp' => $old_revision_date,
+      ))
+      ->execute();
+    $this->drupalPost("node/$node->nid/revisions/{$nodes[2]->vid}/revert", array(), t('Revert'));
+    $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.', array(
+      '@type' => 'Basic page',
+      '%title' => $nodes[2]->title,
+      '%revision-date' => format_date($old_revision_date),
+    )));
+  }
+}
diff --git a/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionEditTest.php b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionEditTest.php
new file mode 100644
index 0000000..f9190ca
--- /dev/null
+++ b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionEditTest.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\node_revision\Tests\NodeRevisionEditTest.
+ */
+
+namespace Drupal\node_revision\Tests;
+
+use Drupal\Core\Language\Language;
+
+/**
+ * Tests the node edit functionality with revisions.
+ */
+class NodeRevisionEditTest extends NodeRevisionTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Node revision edit',
+      'description' => 'Create a node and test node edit functionality with revisions.',
+      'group' => 'Node Revisioning',
+    );
+  }
+
+  /**
+   * Checks node edit functionality.
+   */
+  function testNodeRevisionEdit() {
+    $web_user = $this->drupalCreateUser(array('edit own page content', 'create page content'));
+    $this->drupalLogin($web_user);
+
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
+    $title_key = "title";
+    $body_key = "body[$langcode][0][value]";
+    // Create node to edit.
+    $edit = array();
+    $edit[$title_key] = $this->randomName(8);
+    $edit[$body_key] = $this->randomName(16);
+    $this->drupalPost('node/add/page', $edit, t('Save'));
+
+    // Login as a second administrator user.
+    $second_web_user = $this->drupalCreateUser(array('administer nodes', 'edit any page content'));
+    $this->drupalLogin($second_web_user);
+
+    // Check that the node exists in the database.
+    $node = $this->drupalGetNodeByTitle($edit[$title_key]);
+    $this->assertTrue($node, 'Node found in database.');
+
+    // Edit the same node, creating a new revision.
+    $this->drupalGet("node/$node->nid/edit");
+    $edit = array();
+    $edit['title'] = $this->randomName(8);
+    $edit[$body_key] = $this->randomName(16);
+    $edit['revision'] = TRUE;
+    $this->drupalPost(NULL, $edit, t('Save and keep published'));
+
+    // Ensure that the node revision has been created.
+    $revised_node = $this->drupalGetNodeByTitle($edit['title'], TRUE);
+    $this->assertNotIdentical($node->vid, $revised_node->vid, 'A new revision has been created.');
+    // Ensure that the node author is preserved when it was not changed in the
+    // edit form.
+    $this->assertIdentical($node->uid, $revised_node->uid, 'The node author has been preserved.');
+    // Ensure that the revision authors are different since the revisions were
+    // made by different users.
+    $first_node_version = node_revision_load($node->vid);
+    $second_node_version = node_revision_load($revised_node->vid);
+    $this->assertNotIdentical($first_node_version->revision_uid, $second_node_version->revision_uid, 'Each revision has a distinct user.');
+  }
+
+}
diff --git a/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionPermissionsTest.php b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionPermissionsTest.php
new file mode 100644
index 0000000..22ba714
--- /dev/null
+++ b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionPermissionsTest.php
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\node_revision\Tests\NodeRevisionPermissionsTest.
+ */
+
+namespace Drupal\node_revision\Tests;
+
+/**
+ * Tests user permissions for node revisions.
+ */
+class NodeRevisionPermissionsTest extends NodeRevisionTestBase {
+  protected $node_revisions = array();
+  protected $accounts = array();
+
+  // Map revision permission names to node revision access ops.
+  protected $map = array(
+    'view' => 'view all revisions',
+    'update' => 'revert all revisions',
+    'delete' => 'delete all revisions',
+  );
+
+  // Map revision permission names to node type revision access ops.
+  protected $type_map = array(
+    'view' => 'view page revisions',
+    'update' => 'revert page revisions',
+    'delete' => 'delete page revisions',
+  );
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node revision permissions',
+      'description' => 'Tests user permissions for node revision operations.',
+      'group' => 'Node Revisioning',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+
+    $types = array('page', 'article');
+
+    foreach ($types as $type) {
+      // Create a node with several revisions.
+      $nodes[$type] = $this->drupalCreateNode(array('type' => $type));
+      $this->node_revisions[$type][] = $nodes[$type];
+
+      for ($i = 0; $i < 3; $i++) {
+        // Create a revision for the same nid and settings with a random log.
+        $revision = clone $nodes[$type];
+        $revision->setNewRevision();
+        $revision->log = $this->randomName(32);
+        $revision->save();
+        $this->node_revisions[$type][] = $revision;
+      }
+    }
+  }
+
+  /**
+   * Tests general revision access permissions.
+   */
+  function testNodeRevisionAccessAnyType() {
+    // Create three users, one with each revision permission.
+    foreach ($this->map as $op => $permission) {
+      // Create the user.
+      $account = $this->drupalCreateUser(
+        array(
+          'access content',
+          'edit any page content',
+          'delete any page content',
+          $permission,
+        )
+      );
+      $account->op = $op;
+      $this->accounts[] = $account;
+    }
+
+    // Create an admin account (returns TRUE for all revision permissions).
+    $admin_account = $this->drupalCreateUser(array('access content', 'administer nodes'));
+    $admin_account->is_admin = TRUE;
+    $this->accounts['admin'] = $admin_account;
+    $accounts['admin'] = $admin_account;
+
+    // Create a normal account (returns FALSE for all revision permissions).
+    $normal_account = $this->drupalCreateUser();
+    $normal_account->op = FALSE;
+    $this->accounts[] = $normal_account;
+    $accounts[] = $normal_account;
+    $revision = $this->node_revisions['page'][1];
+
+    $parameters = array(
+      'op' => array_keys($this->map),
+      'account' => $this->accounts,
+    );
+
+    $permutations = $this->generatePermutations($parameters);
+
+    foreach ($permutations as $case) {
+      // Skip this test if there are no revisions for the node.
+      if (!($revision->isDefaultRevision() && (db_query('SELECT COUNT(vid) FROM {node_field_revision} WHERE nid = :nid', array(':nid' => $revision->nid))->fetchField() == 1 || $case['op'] == 'update' || $case['op'] == 'delete'))) {
+        if (!empty($case['account']->is_admin) || user_access($this->map[$case['op']], $case['account'])) {
+          $this->assertTrue(_node_revision_access($revision, $case['op'], $case['account']), "{$this->map[$case['op']]} granted.");
+        }
+        else {
+          $this->assertFalse(_node_revision_access($revision, $case['op'], $case['account']), "{$this->map[$case['op']]} not granted.");
+        }
+      }
+    }
+
+    // Test that access is FALSE for a node administrator with an invalid $node
+    // or $op parameters.
+    $admin_account = $accounts['admin'];
+    $this->assertFalse(_node_revision_access($revision, 'invalid-op', $admin_account), '_node_revision_access() returns FALSE with an invalid op.');
+  }
+
+  /**
+   * Tests revision access permissions for a specific content type.
+   */
+  function testNodeRevisionAccessPerType() {
+    // Create three users, one with each revision permission.
+    foreach ($this->type_map as $op => $permission) {
+      // Create the user.
+      $account = $this->drupalCreateUser(
+        array(
+          'access content',
+          'edit any page content',
+          'delete any page content',
+          $permission,
+        )
+      );
+      $account->op = $op;
+      $accounts[] = $account;
+    }
+
+    $parameters = array(
+      'op' => array_keys($this->type_map),
+      'account' => $accounts,
+    );
+
+    // Test that the accounts have access to the correspoding page revision permissions.
+    $revision = $this->node_revisions['page'][1];
+
+    $permutations = $this->generatePermutations($parameters);
+    foreach ($permutations as $case) {
+      // Skip this test if there are no revisions for the node.
+      if (!($revision->isDefaultRevision() && (db_query('SELECT COUNT(vid) FROM {node_field_revision} WHERE nid = :nid', array(':nid' => $revision->nid))->fetchField() == 1 || $case['op'] == 'update' || $case['op'] == 'delete'))) {
+        if (!empty($case['account']->is_admin) || user_access($this->type_map[$case['op']], $case['account'])) {
+          $this->assertTrue(_node_revision_access($revision, $case['op'], $case['account']), "{$this->type_map[$case['op']]} granted.");
+        }
+        else {
+          $this->assertFalse(_node_revision_access($revision, $case['op'], $case['account']), "{$this->type_map[$case['op']]} not granted.");
+        }
+      }
+    }
+
+    // Test that the accounts have no access to the article revisions.
+    $revision = $this->node_revisions['article'][1];
+
+    foreach ($permutations as $case) {
+      $this->assertFalse(_node_revision_access($revision, $case['op'], $case['account']), "{$this->type_map[$case['op']]} did not grant revision permission for articles.");
+    }
+  }
+}
diff --git a/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionPreviewTest.php b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionPreviewTest.php
new file mode 100644
index 0000000..5040883
--- /dev/null
+++ b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionPreviewTest.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\node_revision\Tests\NodeRevisionPreviewTest.
+ */
+
+namespace Drupal\node_revision\Tests;
+
+use Drupal\Core\Language\Language;
+
+/**
+ * Tests the node revision preview functionality.
+ */
+class NodeRevisionPreviewTest extends NodeRevisionTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node revision preview',
+      'description' => 'Test node preview functionality with revisions.',
+      'group' => 'Node Revisioning',
+    );
+  }
+
+  /**
+   * Checks the node preview functionality, when using revisions.
+   */
+  function testNodeRevisionPreview() {
+    $web_user = $this->drupalCreateUser(array('edit own page content', 'create page content'));
+    $this->drupalLogin($web_user);
+
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
+    $title_key = "title";
+    $body_key = "body[$langcode][0][value]";
+    // Force a new revision on "Basic page" content.
+    $this->container->get('config.factory')->get('node.type.page')->set('settings.node.options', array('status', 'revision'))->save();
+
+    // Fill in node creation form and preview node.
+    $edit = array();
+    $edit[$title_key] = $this->randomName(8);
+    $edit[$body_key] = $this->randomName(16);
+    $edit['log'] = $this->randomName(32);
+    $this->drupalPost('node/add/page', $edit, t('Preview'));
+
+    // Check that the preview is displaying the title, body and term.
+    $this->assertTitle(t('Preview | Drupal'), 'Basic page title is preview.');
+    $this->assertText($edit[$title_key], 'Title displayed.');
+    $this->assertText($edit[$body_key], 'Body displayed.');
+
+    // Check that the title, body and term fields are displayed with the correct values.
+    $this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.');
+    $this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.');
+
+    // Check that the log field has the correct value.
+    $this->assertFieldByName('log', $edit['log'], 'Log field displayed.');
+  }
+
+}
diff --git a/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionTest.php b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionTest.php
new file mode 100644
index 0000000..1d12b87
--- /dev/null
+++ b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionTest.php
@@ -0,0 +1,206 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\node_revision\Tests\NodeRevisionsTest.
+ */
+
+namespace Drupal\node_revision\Tests;
+
+use Drupal\Core\Language\Language;
+
+/**
+ * Tests the node revision functionality.
+ */
+class NodeRevisionTest extends NodeRevisionTestBase {
+  protected $nodes;
+  protected $logs;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node revisions by type',
+      'description' => 'Create a node with revisions and test viewing, saving, reverting, and deleting revisions for users with access for this content type.',
+      'group' => 'Node Revisioning',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+
+    // Create and log in user.
+    $web_user = $this->drupalCreateUser(
+      array(
+        'view page revisions',
+        'revert page revisions',
+        'delete page revisions',
+        'edit any page content',
+        'delete any page content'
+      )
+    );
+
+    $this->drupalLogin($web_user);
+
+    // Create initial node.
+    $node = $this->drupalCreateNode();
+    $settings = get_object_vars($node);
+    $settings['revision'] = 1;
+    $settings['isDefaultRevision'] = TRUE;
+
+    $nodes = array();
+    $logs = array();
+
+    // Get original node.
+    $nodes[] = clone $node;
+
+    // Create three revisions.
+    $revision_count = 3;
+    for ($i = 0; $i < $revision_count; $i++) {
+      $logs[] = $node->log = $this->randomName(32);
+
+      // Create revision with a random title and body and update variables.
+      $node->title = $this->randomName();
+      $node->body[$node->language()->id][0] = array(
+        'value' => $this->randomName(32),
+        'format' => filter_default_format(),
+      );
+      $node->setNewRevision();
+      $node->save();
+
+      $node = node_load($node->nid); // Make sure we get revision information.
+      $nodes[] = clone $node;
+    }
+
+    $this->nodes = $nodes;
+    $this->logs = $logs;
+  }
+
+  /**
+   * Checks node revision related operations.
+   */
+  function testRevisions() {
+    $nodes = $this->nodes;
+    $logs = $this->logs;
+
+    // Get last node for simple checks.
+    $node = $nodes[3];
+
+    // Confirm the correct revision text appears on "view revisions" page.
+    $this->drupalGet("node/$node->nid/revisions/$node->vid/view");
+    $this->assertText($node->body[Language::LANGCODE_NOT_SPECIFIED][0]['value'], 'Correct text displays for version.');
+
+    // Confirm the correct log message appears on "revisions overview" page.
+    $this->drupalGet("node/$node->nid/revisions");
+    foreach ($logs as $log) {
+      $this->assertText($log, 'Log message found.');
+    }
+
+    // Confirm that this is the default revision.
+    $this->assertTrue($node->isDefaultRevision(), 'Third node revision is the default one.');
+
+    // Confirm that revisions revert properly.
+    $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/revert", array(), t('Revert'));
+    $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.',
+                        array('@type' => 'Basic page', '%title' => $nodes[1]->label(),
+                              '%revision-date' => format_date($nodes[1]->revision_timestamp))), 'Revision reverted.');
+    $reverted_node = node_load($node->nid, TRUE);
+    $this->assertTrue(($nodes[1]->body[Language::LANGCODE_NOT_SPECIFIED][0]['value'] == $reverted_node->body[Language::LANGCODE_NOT_SPECIFIED][0]['value']), 'Node reverted correctly.');
+
+    // Confirm that this is not the default version.
+    $node = node_revision_load($node->vid);
+    $this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the default one.');
+
+    // Confirm revisions delete properly.
+    $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/delete", array(), t('Delete'));
+    $this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.',
+                        array('%revision-date' => format_date($nodes[1]->revision_timestamp),
+                              '@type' => 'Basic page', '%title' => $nodes[1]->label())), 'Revision deleted.');
+    $this->assertTrue(db_query('SELECT COUNT(vid) FROM {node_field_revision} WHERE nid = :nid and vid = :vid', array(':nid' => $node->nid, ':vid' => $nodes[1]->vid))->fetchField() == 0, 'Revision not found.');
+
+    // Set the revision timestamp to an older date to make sure that the
+    // confirmation message correctly displays the stored revision date.
+    $old_revision_date = REQUEST_TIME - 86400;
+    db_update('node_field_revision')
+      ->condition('vid', $nodes[2]->vid)
+      ->fields(array(
+        'revision_timestamp' => $old_revision_date,
+      ))
+      ->execute();
+    $this->drupalPost("node/$node->nid/revisions/{$nodes[2]->vid}/revert", array(), t('Revert'));
+    $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.', array(
+      '@type' => 'Basic page',
+      '%title' => $nodes[2]->label(),
+      '%revision-date' => format_date($old_revision_date),
+    )));
+
+    // Make a new revision and set it to not be default.
+    // This will create a new revision that is not "front facing".
+    $new_node_revision = clone $node;
+    $new_body = $this->randomName();
+    $new_node_revision->body[Language::LANGCODE_NOT_SPECIFIED][0]['value'] = $new_body;
+    // Save this as a non-default revision.
+    $new_node_revision->setNewRevision();
+    $new_node_revision->isDefaultRevision = FALSE;
+    $new_node_revision->save();
+
+    $this->drupalGet("node/$node->nid");
+    $this->assertNoText($new_body, 'Revision body text is not present on default version of node.');
+
+    // Verify that the new body text is present on the revision.
+    $this->drupalGet("node/$node->nid/revisions/" . $new_node_revision->vid . "/view");
+    $this->assertText($new_body, 'Revision body text is present when loading specific revision.');
+
+    // Verify that the non-default revision vid is greater than the default
+    // revision vid.
+    $default_revision = db_select('node', 'n')
+      ->fields('n', array('vid'))
+      ->condition('nid', $node->nid)
+      ->execute()
+      ->fetchCol();
+    $default_revision_vid = $default_revision[0];
+    $this->assertTrue($new_node_revision->vid > $default_revision_vid, 'Revision vid is greater than default revision vid.');
+  }
+
+  /**
+   * Checks that revisions are correctly saved without log messages.
+   */
+  function testNodeRevisionWithoutLogMessage() {
+    // Create a node with an initial log message.
+    $log = $this->randomName(10);
+    $node = $this->drupalCreateNode(array('log' => $log));
+
+    // Save over the same revision and explicitly provide an empty log message
+    // (for example, to mimic the case of a node form submitted with no text in
+    // the "log message" field), and check that the original log message is
+    // preserved.
+    $new_title = $this->randomName(10) . 'testNodeRevisionWithoutLogMessage1';
+
+    $node = clone $node;
+    $node->title = $new_title;
+    $node->log = '';
+    $node->setNewRevision(FALSE);
+
+    $node->save();
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertText($new_title, 'New node title appears on the page.');
+    $node_revision = node_load($node->nid, TRUE);
+    $this->assertEqual($node_revision->log, $log, 'After an existing node revision is re-saved without a log message, the original log message is preserved.');
+
+    // Create another node with an initial log message.
+    $node = $this->drupalCreateNode(array('log' => $log));
+
+    // Save a new node revision without providing a log message, and check that
+    // this revision has an empty log message.
+    $new_title = $this->randomName(10) . 'testNodeRevisionWithoutLogMessage2';
+
+    $node = clone $node;
+    $node->title = $new_title;
+    $node->setNewRevision();
+    $node->log = NULL;
+
+    $node->save();
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertText($new_title, 'New node title appears on the page.');
+    $node_revision = node_load($node->nid, TRUE);
+    $this->assertTrue(empty($node_revision->log), 'After a new node revision is saved with an empty log message, the log message for the node is empty.');
+  }
+}
diff --git a/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionTestBase.php b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionTestBase.php
new file mode 100644
index 0000000..51e0ca3
--- /dev/null
+++ b/core/modules/node_revision/lib/Drupal/node_revision/Tests/NodeRevisionTestBase.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\node_revision\Tests\NodeRevisionTestBase.
+ */
+
+namespace Drupal\node_revision\Tests;
+
+use Drupal\Core\Session\AccountInterface;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Sets up page and article content types.
+ */
+abstract class NodeRevisionTestBase extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('node', 'node_revision');
+
+  function setUp() {
+    parent::setUp();
+
+    // Create Basic page and Article node types.
+    if ($this->profile != 'standard') {
+      $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+      $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+    }
+  }
+
+}
diff --git a/core/modules/node_revision/node_revision.api.php b/core/modules/node_revision/node_revision.api.php
new file mode 100644
index 0000000..4eb817d
--- /dev/null
+++ b/core/modules/node_revision/node_revision.api.php
@@ -0,0 +1,38 @@
+<?php
+
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * @file
+ * Hooks provided by the Node Revision module.
+ */
+
+/**
+ * Here is a list of the node and entity hooks that are invoked, field
+ * operations, and other steps that take place during node operations:
+ * - Deleting a node revision (calling node_revision_delete()):
+ *   - Node is loaded (see Loading section above)
+ *   - Revision information is deleted from database
+ *   - hook_node_revision_delete() (all)
+ *   - field_attach_delete_revision()
+ * @}
+ */
+
+/**
+ * Respond to deletion of a node revision.
+ *
+ * This hook is invoked from node_revision_delete() after the revision has been
+ * removed from the node_revision table, and before
+ * field_attach_delete_revision() is called.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $node
+ *   The node revision (node object) that is being deleted.
+ *
+ * @ingroup node_api_hooks
+ */
+function hook_node_revision_delete(\Drupal\Core\Entity\EntityInterface $node) {
+  db_delete('mytable')
+    ->condition('vid', $node->vid)
+    ->execute();
+}
+
diff --git a/core/modules/node_revision/node_revision.info.yml b/core/modules/node_revision/node_revision.info.yml
new file mode 100644
index 0000000..a38c71c
--- /dev/null
+++ b/core/modules/node_revision/node_revision.info.yml
@@ -0,0 +1,9 @@
+name: Node Revisioning
+type: module
+description: 'Allows content to be versioned.'
+package: Core
+version: VERSION
+core: 8.x
+configure: admin/structure/types
+dependencies:
+  - node
diff --git a/core/modules/node_revision/node_revision.js b/core/modules/node_revision/node_revision.js
new file mode 100644
index 0000000..f82bb17
--- /dev/null
+++ b/core/modules/node_revision/node_revision.js
@@ -0,0 +1,30 @@
+/**
+ * @file
+ * Defines Javascript behaviors for the node revision module.
+ */
+
+(function ($) {
+
+"use strict";
+
+Drupal.behaviors.nodeDetailsSummaries = {
+  attach: function (context) {
+    var $context = $(context);
+    $context.find('.node-form-revision-information').drupalSetSummary(function (context) {
+      var $context = $(context);
+      var revisionCheckbox = $context.find('.form-item-revision input');
+
+      // Return 'New revision' if the 'Create new revision' checkbox is checked,
+      // or if the checkbox doesn't exist, but the revision log does. For users
+      // without the "Administer content" permission the checkbox won't appear,
+      // but the revision log will if the content type is set to auto-revision.
+      if (revisionCheckbox.is(':checked') || (!revisionCheckbox.length && $context.find('.form-item-log textarea').length)) {
+        return Drupal.t('New revision');
+      }
+
+      return Drupal.t('No revision');
+    });
+  }
+};
+
+})(jQuery);
diff --git a/core/modules/node_revision/node_revision.module b/core/modules/node_revision/node_revision.module
new file mode 100644
index 0000000..f8e8031
--- /dev/null
+++ b/core/modules/node_revision/node_revision.module
@@ -0,0 +1,303 @@
+<?php
+
+/**
+ * @file
+ * Core module that allows content to be revisioned.
+ */
+
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Implements hook_help().
+ */
+function node_revision_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#node':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The Node revision module allows site content to be revisioned. For more information, see the online handbook entry for <a href="@node">Node module</a>.', array('@node' => 'http://drupal.org/documentation/modules/node')) . '</p>';
+      $output .= '<h3>' . t('Uses') . '</h3>';
+      $output .= '<dl>';
+      $output .= '<dt>' . t('Creating revisions') . '</dt>';
+      $output .= '<dd>' . t('The Node revision module enables you to create multiple versions of any content, and revert to older versions using the <em>Revision information</em> settings.') . '</dd>';
+      $output .= '<dt>' . t('User permissions') . '</dt>';
+      $output .= '<dd>' . t('The Node revision module makes a number of additional permissions available for each content type, which can be set by role on the <a href="@permissions">permissions page</a>.', array('@permissions' => url('admin/people/permissions', array('fragment' => 'module-node-revision')))) . '</dd>';
+      $output .= '</dl>';
+      return $output;
+
+    case 'node/%/revisions':
+      return '<p>' . t('Revisions allow you to track differences between multiple versions of your content, and revert back to older versions.') . '</p>';
+  }
+}
+
+/**
+ * Implements hook_admin_paths().
+ */
+function node_revision_admin_paths() {
+  if (variable_get('node_admin_theme')) {
+    $paths = array(
+      'node/*/revisions' => TRUE,
+      'node/*/revisions/*/revert' => TRUE,
+      'node/*/revisions/*/delete' => TRUE,
+    );
+    return $paths;
+  }
+}
+
+/**
+ * Loads a node revision from the database.
+ *
+ * @param int $nid
+ *   The node revision id.
+ *
+ * @return \Drupal\node\Node|null
+ *   A fully-populated node entity or NULL if the node is not found.
+ */
+function node_revision_load($vid = NULL) {
+  return entity_revision_load('node', $vid);
+}
+
+/**
+ * Deletes a node revision.
+ *
+ * @param $revision_id
+ *   The revision ID to delete.
+ *
+ * @return
+ *   TRUE if the revision deletion was successful; otherwise, FALSE.
+ */
+function node_revision_delete($revision_id) {
+  entity_revision_delete('node', $revision_id);
+}
+
+/**
+ * Implements hook_permission().
+ */
+function node_revision_permission() {
+  $perms = array(
+    'view all revisions' => array(
+      'title' => t('View all revisions'),
+    ),
+    'revert all revisions' => array(
+      'title' => t('Revert all revisions'),
+      'description' => t('Role requires permission <em>view revisions</em> and <em>edit rights</em> for nodes in question, or <em>administer nodes</em>.'),
+    ),
+    'delete all revisions' => array(
+      'title' => t('Delete all revisions'),
+      'description' => t('Role requires permission to <em>view revisions</em> and <em>delete rights</em> for nodes in question, or <em>administer nodes</em>.'),
+    ),
+  );
+
+  // Generate standard node permissions for all applicable node types.
+  foreach (node_permissions_get_configured_types() as $name => $type) {
+    $perms += node_revision_list_permissions($type);
+  }
+  return $perms;
+}
+
+/**
+ * Implements hook_user_cancel().
+ */
+function node_revision_user_cancel($edit, $account, $method) {
+  switch ($method) {
+    case 'user_cancel_reassign':
+      // Anonymize old revisions.
+      db_update('node_field_revision')
+        ->fields(array('uid' => 0))
+        ->condition('uid', $account->id())
+        ->execute();
+      break;
+  }
+}
+
+/**
+ * Implements hook_user_predelete().
+ */
+function node_revision_user_predelete($account) {
+  // Delete old revisions.
+  $revisions = db_query('SELECT DISTINCT vid FROM {node_field_revision} WHERE uid = :uid', array(':uid' => $account->id()))->fetchCol();
+  foreach ($revisions as $revision) {
+    node_revision_delete($revision);
+  }
+}
+
+/**
+ * Access callback: Checks node revision access.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $node
+ *   The node to check.
+ * @param $op
+ *   (optional) The specific operation being checked. Defaults to 'view.'
+ * @param object $account
+ *   (optional) A user object representing the user for whom the operation is
+ *   to be performed. Determines access for a user other than the current user.
+ *   Defaults to NULL.
+ * @param $langcode
+ *   (optional) Language code for the variant of the node. Different language
+ *   variants might have different permissions associated. If NULL, the
+ *   original langcode of the node is used. Defaults to NULL.
+ *
+ * @return
+ *   TRUE if the operation may be performed, FALSE otherwise.
+ *
+ * @see node_menu()
+ */
+function _node_revision_access(EntityInterface $node, $op = 'view', $account = NULL, $langcode = NULL) {
+  return Drupal::service('access_check.node_revision')->checkAccess($node, $op, $account, $langcode);
+}
+
+/**
+ * Implements hook_menu().
+ */
+function node_revision_menu() {
+  $items['node/%node/revisions'] = array(
+    'title' => 'Revisions',
+    'page callback' => 'node_revision_overview',
+    'page arguments' => array(1),
+    'access callback' => '_node_revision_access',
+    'access arguments' => array(1),
+    'weight' => 20,
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'node_revision.pages.inc',
+  );
+  $items['node/%node/revisions/%node_revision/view'] = array(
+    'title' => 'Revisions',
+    'page callback' => 'node_show',
+    'page arguments' => array(3, TRUE),
+    'access callback' => '_node_revision_access',
+    'access arguments' => array(3),
+  );
+  $items['node/%node/revisions/%node_revision/revert'] = array(
+    'title' => 'Revert to earlier revision',
+    'route_name' => 'node_revision_revert_confirm',
+  );
+  $items['node/%node/revisions/%node_revision/delete'] = array(
+    'title' => 'Delete earlier revision',
+    'route_name' => 'node_revision_delete_confirm',
+  );
+  return $items;
+}
+
+/**
+ * Returns a list of all the existing revision numbers for the node passed in.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $node
+ *   The node entity.
+ *
+ * @return
+ *   An associative array keyed by node revision number.
+ */
+function node_revision_list(EntityInterface $node) {
+  $revisions = array();
+  $result = db_query('SELECT nfr.vid, nfr.title, nfr.log, nfr.revision_uid AS uid, n.vid AS current_vid, nfr.revision_timestamp, u.name FROM {node_field_revision} nfr LEFT JOIN {node} n ON n.vid = nfr.vid INNER JOIN {users} u ON u.uid = nfr.revision_uid WHERE nfr.nid = :nid AND nfr.default_langcode = 1 ORDER BY nfr.vid DESC', array(':nid' => $node->id()));
+  foreach ($result as $revision) {
+    $revisions[$revision->vid] = $revision;
+  }
+
+  return $revisions;
+}
+
+/**
+ * Helper function to generate standard node permission list for a given type.
+ *
+ * @param $name
+ *   The machine name of the node type.
+ *
+ * @return array
+ *   An array of permission names and descriptions.
+ */
+function node_revision_list_permissions($type) {
+  // Build standard list of node revision permissions for this type.
+  $perms = array(
+    "view $type->type revisions" => array(
+      'title' => t('%type_name: View revisions', array('%type_name' => $type->name)),
+    ),
+    "revert $type->type revisions" => array(
+      'title' => t('%type_name: Revert revisions', array('%type_name' => $type->name)),
+      'description' => t('Role requires permission <em>view revisions</em> and <em>edit rights</em> for nodes in question, or <em>administer nodes</em>.'),
+    ),
+    "delete $type->type revisions" => array(
+      'title' => t('%type_name: Delete revisions', array('%type_name' => $type->name)),
+      'description' => t('Role requires permission to <em>view revisions</em> and <em>delete rights</em> for nodes in question, or <em>administer nodes</em>.'),
+    ),
+  );
+  return $perms;
+}
+
+/**
+ * Implements hook_form_BASE_FORM_ID_alter() for node_form().
+ *
+ * @see path_form_element_validate()
+ */
+function node_revision_form_node_form_alter(array &$form, array $form_state) {
+  $node = $form_state['controller']->getEntity();
+
+  // Add a log field if the "Create new revision" option is checked, or if
+  // the current user has the ability to check that option.
+  $form['revision_information'] = array(
+    '#type' => 'details',
+    '#group' => 'advanced',
+    '#title' => t('Revision information'),
+    // Collapsed by default when "Create new revision" is unchecked.
+    '#collapsed' => !$node->isNewRevision(),
+    '#attributes' => array(
+      'class' => array('node-form-revision-information'),
+    ),
+    '#attached' => array(
+      'js' => array(drupal_get_path('module', 'node_revision') . '/node_revision.js'),
+    ),
+    '#weight' => 20,
+    '#access' => $node->isNewRevision() || user_access('administer nodes'),
+  );
+
+  $form['revision_information']['revision']['revision'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Create new revision'),
+    '#default_value' => $node->isNewRevision(),
+    '#access' => user_access('administer nodes'),
+  );
+
+  $form['revision_information']['revision']['log'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Revision log message'),
+    '#rows' => 4,
+    '#default_value' => !empty($node->log) ? $node->log : '',
+    '#description' => t('Briefly describe the changes you have made.'),
+    '#states' => array(
+      'visible' => array(
+        ':input[name="revision"]' => array('checked' => TRUE),
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_node_submit().
+ */
+function node_revision_node_submit(EntityInterface $node, $form, $form_state) {
+  // Save as a new revision if requested to do so, with the current user as
+  // revision author and the current time as revision creation time.
+  if (!empty($form_state['values']['revision'])) {
+    $node->setNewRevision();
+    global $user;
+    $node->setRevisionAuthorId($user->id());
+    $node->setRevisionCreationTime(REQUEST_TIME);
+  }
+}
+
+/**
+ * Implements hook_library_info().
+ */
+function node_revision_library_info() {
+  $libraries['drupal.node'] = array(
+    'title' => 'Node Revision',
+    'version' => VERSION,
+    'js' => array(
+      drupal_get_path('module', 'node_revision') . '/node_revision.js' => array(),
+    ),
+//    'dependencies' => array(
+//      array('node', 'node'),
+//    ),
+  );
+  return $libraries;
+}
diff --git a/core/modules/node_revision/node_revision.pages.inc b/core/modules/node_revision/node_revision.pages.inc
new file mode 100644
index 0000000..4a41aa3
--- /dev/null
+++ b/core/modules/node_revision/node_revision.pages.inc
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Callbacks for managing revisions.
+ *
+ * @see node_revision_menu()
+ */
+
+/**
+ * Page callback: Generates an overview table of older revisions of a node.
+ *
+ * @param object $node
+ *   A node object.
+ *
+ * @return array
+ *   An array as expected by drupal_render().
+ *
+ * @see node_menu()
+ */
+function node_revision_overview($node) {
+  drupal_set_title(t('Revisions for %title', array('%title' => $node->label())), PASS_THROUGH);
+
+  $header = array(t('Revision'), t('Operations'));
+
+  $revisions = node_revision_list($node);
+
+  $rows = array();
+  $type = $node->type;
+
+  $revert_permission = FALSE;
+  if ((user_access("revert $type revisions") || user_access('revert all revisions') || user_access('administer nodes')) && node_access('update', $node)) {
+    $revert_permission = TRUE;
+  }
+  $delete_permission = FALSE;
+  if ((user_access("delete $type revisions") || user_access('delete all revisions') || user_access('administer nodes')) && node_access('delete', $node)) {
+    $delete_permission = TRUE;
+  }
+  foreach ($revisions as $revision) {
+    $row = array();
+    $type = $node->type;
+    if ($revision->current_vid > 0) {
+      $username = array(
+        '#theme' => 'username',
+        '#account' => user_load($revision->uid),
+      );
+      $row[] = array('data' => t('!date by !username', array('!date' => l(format_date($revision->revision_timestamp, 'short'), "node/$node->nid"), '!username' => drupal_render($username)))
+                               . (($revision->log != '') ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : ''),
+                     'class' => array('revision-current'));
+      $row[] = array('data' => drupal_placeholder(t('current revision')), 'class' => array('revision-current'));
+    }
+    else {
+      $username = array(
+        '#theme' => 'username',
+        '#account' => user_load($revision->uid),
+      );
+      $row[] = t('!date by !username', array('!date' => l(format_date($revision->revision_timestamp, 'short'), "node/$node->nid/revisions/$revision->vid/view"), '!username' => drupal_render($username)))
+               . (($revision->log != '') ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : '');
+      if ($revert_permission) {
+        $links['revert'] = array(
+          'title' => t('Revert'),
+          'href' => "node/$node->nid/revisions/$revision->vid/revert",
+        );
+      }
+      if ($delete_permission) {
+        $links['delete'] = array(
+          'title' => t('Delete'),
+          'href' => "node/$node->nid/revisions/$revision->vid/delete",
+        );
+      }
+      $row[] = array(
+        'data' => array(
+          '#type' => 'operations',
+          '#links' => $links,
+        ),
+      );
+    }
+    $rows[] = $row;
+  }
+
+  $build['node_revisions_table'] = array(
+    '#theme' => 'table',
+    '#rows' => $rows,
+    '#header' => $header,
+    '#attached' => array (
+      'css' => array(drupal_get_path('module', 'node') . '/css/node.admin.css'),
+    ),
+  );
+
+  return $build;
+}
diff --git a/core/modules/node_revision/node_revision.routing.yml b/core/modules/node_revision/node_revision.routing.yml
new file mode 100644
index 0000000..3350952
--- /dev/null
+++ b/core/modules/node_revision/node_revision.routing.yml
@@ -0,0 +1,13 @@
+node_revision_revert_confirm:
+  pattern: '/node/{node}/revisions/{node_revision}/revert'
+  defaults:
+    _form: '\Drupal\node_revision\Form\NodeRevisionRevertForm'
+  requirements:
+    _access_node_revision: 'update'
+
+node_revision_delete_confirm:
+  pattern: '/node/{node}/revisions/{node_revision}/delete'
+  defaults:
+    _form: '\Drupal\node_revision\Form\NodeRevisionDeleteForm'
+  requirements:
+    _access_node_revision: 'delete'
diff --git a/core/modules/node_revision/node_revision.services.yml b/core/modules/node_revision/node_revision.services.yml
new file mode 100644
index 0000000..141538c
--- /dev/null
+++ b/core/modules/node_revision/node_revision.services.yml
@@ -0,0 +1,6 @@
+services:
+  access_check.node_revision:
+    class: Drupal\node_revision\Access\NodeRevisionAccessCheck
+    arguments: ['@plugin.manager.entity', '@database']
+    tags:
+      - { name: access_check }
diff --git a/core/profiles/standard/standard.info.yml b/core/profiles/standard/standard.info.yml
index 2dfadbb..d63d81d 100644
--- a/core/profiles/standard/standard.info.yml
+++ b/core/profiles/standard/standard.info.yml
@@ -5,6 +5,7 @@ version: VERSION
 core: 8.x
 dependencies:
   - node
+  - node_revision
   - history
   - block
   - breakpoint
