diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
index 6d0a3f4..c4c2874 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
@@ -137,6 +137,16 @@ public function loadByProperties(array $values = array()) {
   }
 
   /**
+   * Returns the config prefix used by the configuration entity type.
+   *
+   * @return string
+   *   The full configuration prefix, for example `views.view.`.
+   */
+  public function getConfigPrefix() {
+    return $this->entityInfo['config_prefix'] . '.';
+  }
+
+  /**
    * Builds the query to load the entity.
    *
    * This has full revision support. For entities requiring special queries,
@@ -159,7 +169,7 @@ public function loadByProperties(array $values = array()) {
    */
   protected function buildQuery($ids, $revision_id = FALSE) {
     $config_class = $this->entityInfo['class'];
-    $prefix = $this->entityInfo['config_prefix'] . '.';
+    $prefix = $this->getConfigPrefix();
 
     // Load all of the configuration entities.
     if ($ids === NULL) {
@@ -251,7 +261,7 @@ public function delete(array $entities) {
     }
 
     foreach ($entities as $id => $entity) {
-      $config = config($this->entityInfo['config_prefix'] . '.' . $entity->id());
+      $config = config($this->getConfigPrefix() . $entity->id());
       $config->delete();
 
       // Remove the entity from the manifest file.
@@ -273,7 +283,7 @@ public function delete(array $entities) {
    *   When attempting to save a configuration entity that has no ID.
    */
   public function save(EntityInterface $entity) {
-    $prefix = $this->entityInfo['config_prefix'] . '.';
+    $prefix = $this->getConfigPrefix();
 
     // Configuration entity IDs are strings, and '0' is a valid ID.
     $id = $entity->id();
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php b/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php
index 3f39af8..0d666c6 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php
@@ -26,7 +26,8 @@
  *   form_controller_class = {
  *     "edit" = "Drupal\views_ui\ViewEditFormController",
  *     "add" = "Drupal\views_ui\ViewAddFormController",
- *     "preview" = "Drupal\views_ui\ViewPreviewFormController"
+ *     "preview" = "Drupal\views_ui\ViewPreviewFormController",
+ *     "manage_snapshot" = "Drupal\views_ui\ViewSnapshotManageFormController"
  *   },
  *   config_prefix = "views.view",
  *   fieldable = FALSE,
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/ViewSnapshot.php b/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/ViewSnapshot.php
new file mode 100644
index 0000000..1aceef1
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/ViewSnapshot.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\Core\Entity\ViewSnapshot.
+ */
+
+namespace Drupal\views\Plugin\Core\Entity;
+
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+use Drupal\views\ViewStorageInterface;
+
+/**
+ * Extends the view configuration entity to support some additional properties.
+ *
+ * @Plugin(
+ *   id = "view_snapshot",
+ *   label = @Translation("View Snapshot"),
+ *   module = "views",
+ *   controller_class = "Drupal\views\ViewSnapshotStorageController",
+ *   list_controller_class = "Drupal\views_ui\ViewSnapshotListController",
+ *   config_prefix = "views.view_snapshot",
+ *   form_controller_class = {
+ *     "edit" = "Drupal\views_ui\ViewEditFormController",
+ *     "preview" = "Drupal\views_ui\ViewPreviewFormController",
+ *     "revert" = "Drupal\views_ui\ViewSnapshotRevertFormController",
+ *     "delete" = "Drupal\views_ui\ViewSnapshotDeleteFormController"
+ *   },
+ *   fieldable = FALSE,
+ *   entity_keys = {
+ *     "id" = "snapshotID",
+ *     "label" = "human_name",
+ *     "uuid" = "uuid"
+ *   }
+ * )
+ */
+class ViewSnapShot extends View implements ViewStorageInterface  {
+
+  /**
+   * The timestamp on which the snapshot of the view got created.
+   *
+   * @var int
+   */
+  protected $created;
+
+  /**
+   * A comment created specificly for the snapshot.
+   *
+   * @var string
+   */
+  protected $comment;
+
+  /**
+   * The ID of the snapshot which contains of the name and a number.
+   */
+  public $snapshotID;
+
+  /**
+   * Overrides \Drupal\views\Plugin\Core\Entity\View::id().
+   */
+  public function id() {
+    return $this->get('snapshotID');
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
index 8d6fe06..9de6365 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
@@ -402,7 +402,12 @@ function use_string_group_by() {
   protected function defineOptions() {
     $options = parent::defineOptions();
 
-    $options['label'] = array('default' => $this->definition['title'], 'translatable' => TRUE);
+    $options['label'] = array('default' => '', 'translatable' => TRUE);
+    // Some styles (for example table) should have field labels enabled by
+    // default.
+    if (isset($this->view->style_plugin) && $this->view->style_plugin->defaultFieldLabels()) {
+      $options['label']['default'] = $this->definition['title'];
+    }
     $options['exclude'] = array('default' => FALSE, 'bool' => TRUE);
     $options['alter'] = array(
       'contains' => array(
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/style/StylePluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/style/StylePluginBase.php
index ee8081d..15e8919 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/style/StylePluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/style/StylePluginBase.php
@@ -80,6 +80,13 @@
   protected $usesFields = FALSE;
 
   /**
+   * Should field labels be enabled by default.
+   *
+   * @var bool
+   */
+  protected $defaultFieldLabels = FALSE;
+
+  /**
    * Initialize a style plugin.
    *
    * @param $view
@@ -172,6 +179,15 @@ function uses_tokens() {
   }
 
   /**
+   * Return TRUE if this style enables field labels by default.
+   *
+   * @return bool
+   */
+  public function defaultFieldLabels() {
+    return $this->defaultFieldLabels;
+  }
+
+  /**
    * Return the token replaced row class for the specified row.
    */
   function get_row_class($row_index) {
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/style/Table.php b/core/modules/views/lib/Drupal/views/Plugin/views/style/Table.php
index 5a3e907..014219a 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/style/Table.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/style/Table.php
@@ -59,6 +59,11 @@ class Table extends StylePluginBase {
    */
   public $order;
 
+  /**
+   * Override \Drupal\views\Plugin\views\style\StylePluginBase::defaultFieldLabels
+   */
+  protected $defaultFieldLabels = TRUE;
+
   protected function defineOptions() {
     $options = parent::defineOptions();
 
diff --git a/core/modules/views/lib/Drupal/views/Tests/UI/SnapshotTest.php b/core/modules/views/lib/Drupal/views/Tests/UI/SnapshotTest.php
new file mode 100644
index 0000000..5e63f3b
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Tests/UI/SnapshotTest.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Tests\UI\SnapshotTest.
+ */
+
+namespace Drupal\views\Tests\UI;
+
+/**
+ * Tests the general UI for creating snapshot of views.
+ */
+class SnapshotTest extends UITestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Snapshots',
+      'description' => 'Tests the general UI for creating snapshot of views.',
+      'group' => 'Views UI',
+    );
+  }
+
+  /**
+   * Tests CRUD UI functionality of views snapshots.
+   */
+  public function testCRUDUI() {
+    $view = entity_load('view', 'test_view');
+
+    // Make sure the snapshots link appear on the actual edit UI.
+    $uri = $view->uri();
+    $this->drupalGet($uri['path'] . '/edit');
+    $this->assertLink(t('snapshots'), 0, 'The snapshot link appears');
+
+    $this->clickLink(t('snapshots'), 0);
+    $snapshots_list_url = 'admin/structure/views/nojs/snapshots/test_view';
+    $this->assertUrl($snapshots_list_url);
+
+    $this->assertTitle(format_string("View snapshots: @view_name | @site_name", array('@view_name' => $view->getHumanName(), '@site_name' => config('system.site')->get('name'))), 'The view name is used in title.');
+
+    // Create a snapshot and make sure it got saved correctly.
+    $random_comment = $this->randomName(50);
+    $this->drupalPost(NULL, array('comment' => $random_comment), t('Create snapshot'));
+    $this->drupalGet($snapshots_list_url);
+    $this->assertText('test_view:1', 'A snapshot got created.');
+    $this->assertText($random_comment, 'The comment of the snapshot got saved correctly.');
+
+    // Create a second snapshot, edit it, and make sure the change just got
+    // added to the changed snapshot.
+    $this->drupalGet($snapshots_list_url);
+    $this->drupalPost($snapshots_list_url, array(), t('Create snapshot'));
+
+    $snapshot_1 = entity_load('view_snapshot', 'test_view:1');
+    $snapshot_2 = entity_load('view_snapshot', 'test_view:1');
+
+    // Add a random title, check it on that snapshot and another snapshot.
+    $random_title = $this->randomName();
+    $this->drupalPost("admin/structure/views/nojs/display/{$snapshot_1->id()}/default/title", array('title' => $random_title), t('Apply'));
+    $this->assertText($random_title);
+
+    $this->drupalGet("admin/structure/views/view/$snapshot_1->id()/edit");
+    $this->assertNoText($random_title);
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/ViewSnapshotStorageController.php b/core/modules/views/lib/Drupal/views/ViewSnapshotStorageController.php
new file mode 100644
index 0000000..9d45c35
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/ViewSnapshotStorageController.php
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\ViewSnapshotStorageController.
+ */
+
+namespace Drupal\views;
+use Drupal\views\Plugin\Core\Entity\ViewSnapShot;
+use Drupal\views_ui\ViewUI;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\views\Plugin\Core\Entity\View;
+
+/**
+ * Defines the storage controller class for snapshots of views.
+ */
+class ViewSnapshotStorageController extends ViewStorageController {
+
+  /**
+   * The config prefix used by the controller.
+   *
+   * To be able to support listing of view snapshot revisions by name in a
+   * effective way. Therefore we change the configPrefix from
+   * views.view_revision to views.view_revision.$name with $name the actual name
+   * of the view.
+   *
+   * @var string
+   *
+   * @see \Drupal\views\ViewSnapshotStorageController\loadByProperties()
+   */
+  protected $configPrefix;
+
+  /**
+   * The character/string to split the snapshot ID on.
+   * @var string
+   */
+  static protected $split = ':';
+
+
+  public function __construct($entityType) {
+    parent::__construct($entityType);
+
+    $this->configPrefix = $this->entityInfo['config_prefix'] . '.';
+  }
+
+  /**
+   * Overrides \Drupal\Core\Config\Entity::getConfigPrefix().
+   */
+  public function getConfigPrefix() {
+    return $this->configPrefix;
+  }
+
+  /**
+   * Overrides \Drupal\Core\Config\Entity::loadByProperties().
+   */
+  public function loadByProperties(array $values = array()) {
+    // The config storage controller does not allow to filter by properties,
+    // but let's support at least loading all views snapshots by the name of the
+    // view.
+    if (isset($values['name'])) {
+      $old_prefix = $this->getConfigPrefix();
+      $this->configPrefix = $old_prefix . $values['name'] . static::$split;
+      $list = $this->load();
+      $this->configPrefix =  $old_prefix;
+
+      return $list;
+    }
+    else {
+      return parent::loadByProperties($values);
+    }
+  }
+
+  public function createSnapshot(View $view, array $snapshot_values = array()) {
+    $view_config = entity_get_controller('view')->getProperties($view);
+    $view_config += $snapshot_values + array(
+      'created' => REQUEST_TIME,
+    );
+
+    // Generate the next snapshot id by finding the last snapshot and add +1.
+    $name = $view->get('name');
+    $snapshot_keys = array_keys($this->loadByProperties(array('name' => $name)));
+    $last_snapshot_id = end($snapshot_keys);
+    $revision_id = (int) str_replace($name . static::$split, '', $last_snapshot_id);
+    $next_revision_id = ++$revision_id;
+
+    $view_config['snapshotID'] = $name . static::$split  . $next_revision_id;
+
+    $snapshot = $this->create($view_config);
+    return $snapshot;
+  }
+
+  /**
+   * Revert a view to a certain snapshot.
+   *
+   * @param \Drupal\views\Plugin\Core\Entity\View $view
+   *   The view to revert to a certain snapshot.
+   * @param \Drupal\views\Plugin\Core\Entity\ViewSnapshot $snapshot
+   *   The snapshot to revert to.
+   */
+  public function revertSnapshot(View $view, ViewSnapshot $snapshot) {
+    // Get all values of the snapshot to set it to the main view.
+    $snapshot_properties = $this->getProperties($snapshot);
+    unset($snapshot_properties['created'], $snapshot_properties['comment'], $snapshot_properties['snapshotID'], $snapshot_properties['uuid']);
+
+    // Set all properties of the snapshot to the view and save it.
+    foreach ($snapshot_properties as $property_name => $property_value) {
+      $view->set($property_name, $property_value);
+    }
+    $view->save();
+
+    return $view;
+  }
+
+  /**
+   * Overrides \Drupal\views\ViewStorageController::getProperties().
+   */
+  protected function getProperties(EntityInterface $entity) {
+    $properties = parent::getProperties($entity);
+
+    $names = array(
+      'created',
+      'comment',
+      'snapshotID'
+    );
+
+    foreach ($names as $name) {
+      $properties[$name] = $entity->get($name);
+    }
+
+    return $properties;
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/ViewStorageController.php b/core/modules/views/lib/Drupal/views/ViewStorageController.php
index 05268d2..7fa7f4e 100644
--- a/core/modules/views/lib/Drupal/views/ViewStorageController.php
+++ b/core/modules/views/lib/Drupal/views/ViewStorageController.php
@@ -80,10 +80,11 @@ public function create(array $values) {
    * @param Drupal\Core\Entity\EntityInterface $entity
    */
   protected function attachDisplays(EntityInterface $entity) {
-    if (isset($entity->display) && is_array($entity->display)) {
+    $view_displays = $entity->get('display');
+    if (isset($view_displays) && is_array($view_displays)) {
       $displays = array();
 
-      foreach ($entity->get('display') as $key => $options) {
+      foreach ($view_displays as $key => $options) {
         $options += array(
           'display_options' => array(),
           'display_plugin' => NULL,
diff --git a/core/modules/views/tests/views_test_config/config/views.view.test_view.yml b/core/modules/views/tests/views_test_config/config/views.view.test_view.yml
index 57dd103..2d849a1 100644
--- a/core/modules/views/tests/views_test_config/config/views.view.test_view.yml
+++ b/core/modules/views/tests/views_test_config/config/views.view.test_view.yml
@@ -43,6 +43,6 @@ display:
     display_title: Master
     id: default
     position: '0'
-human_name: ''
+human_name: Test view
 name: test_view
 tag: ''
diff --git a/core/modules/views/views_ui/admin.inc b/core/modules/views/views_ui/admin.inc
index 5b0ae41..c5f1a72 100644
--- a/core/modules/views/views_ui/admin.inc
+++ b/core/modules/views/views_ui/admin.inc
@@ -513,6 +513,18 @@ function views_ui_ajax_forms($key = NULL) {
       'form_id' => 'views_ui_analyze_view_form',
       'args' => array(),
     ),
+    'snapshots' => array(
+      'form_id' => 'views_ui_snapshot_form',
+      'args' => array(),
+    ),
+    'revert-snapshot' => array(
+      'form_id' => 'views_ui_revert_snapshot_form',
+      'args' => array(),
+    ),
+    'delete-snapshot' => array(
+      'form_id' => 'views_ui_delete_snapshot_form',
+      'args' => array(),
+    ),
   );
 
   if ($key) {
@@ -663,6 +675,28 @@ function views_ui_analyze_view_form_submit($form, &$form_state) {
 }
 
 /**
+ * Form submit handler to create a new snapshot.
+ */
+function views_ui_snapshot_add_submit($form, &$form_state) {
+  $view = $form_state['view'];
+  $snapshot_values = array(
+    'created' => REQUEST_TIME,
+    'comment' => $form_state['values'],
+  );
+
+  entity_get_controller('view_snapshot', 'storage')->createSnapshot($view, $snapshot_values);
+
+  $uri = $view->uri();
+//  $form_state['redirect'] = $uri['path'] . '/edit';
+}
+
+/**
+ * Form submit handler to delete an existing snapshot.
+ */
+function views_ui_snapshot_delete_submit($form, &$form_state) {
+}
+
+/**
  * Form builder to edit details of a view.
  */
 function views_ui_edit_details_form($form, &$form_state) {
@@ -2389,3 +2423,51 @@ function views_ui_plugin_list() {
     '#empty' => t('There are no enabled views.'),
   );
 }
+
+/**
+ * Form callback to list snapshots.
+ *
+ * @todo It would make sense to convert this to a snapshot form controller on
+ *   the view.
+ */
+function views_ui_snapshot_form($form, &$form_state) {
+  $view = &$form_state['view'];
+  $form = entity_get_form($view, 'manage_snapshot');
+  return $form;
+}
+
+/**
+ * Form submit handler to create a new snapshot.
+ */
+function views_ui_snapshot_form_create(&$form, &$form_state) {
+  $snapshot_controller = entity_get_controller('view_snapshot');
+
+  $storage = $form_state['view']->get('storage');
+  $snapshot = $snapshot_controller->createSnapshot($storage, array('comment' => $form_state['values']['comment']));
+  $snapshot->save();
+
+  // Show a message and redirect to the edit view.
+  drupal_set_message(t('Snapshot number @id created.', array('@id' => $snapshot->id())));
+  $uri = $storage->uri();
+  $form_state['redirect'] = $uri['path'] . '/edit';
+}
+
+/**
+ * Form controller to revert a view to a snapshot.
+ *
+ * @see \Drupal\views_ui\ViewSnapshotRevertFormController
+ */
+function views_ui_revert_snapshot_form($form, &$form_state) {
+  $snapshot = &$form_state['view'];
+  return entity_get_form($snapshot, 'revert');
+}
+
+/**
+ * Form controller to delete a snapshot.
+ *
+ * @see \Drupal\views_ui\ViewSnapshotDeleteFormController
+ */
+function views_ui_delete_snapshot_form($form, &$form_state) {
+  $snapshot = &$form_state['view'];
+  return entity_get_form($snapshot, 'delete');
+}
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
index 853d5c9..5daef7f 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
@@ -16,20 +16,6 @@
 class ViewEditFormController extends ViewFormControllerBase {
 
   /**
-   * Overrides Drupal\Core\Entity\EntityFormController::getEntity().
-   */
-  public function getEntity(array $form_state) {
-    return isset($form_state['view']) ? $form_state['view'] : NULL;
-  }
-
-  /**
-   * Overrides Drupal\Core\Entity\EntityFormController::setEntity().
-   */
-  public function setEntity(EntityInterface $entity, array &$form_state) {
-    $form_state['view'] = $entity;
-  }
-
-  /**
    * Overrides Drupal\Core\Entity\EntityFormController::form().
    */
   public function form(array $form, array &$form_state, EntityInterface $view) {
@@ -643,6 +629,11 @@ public function renderDisplayTop(ViewUI $view) {
           'href' => "admin/structure/views/nojs/reorder-displays/{$view->get('name')}/$display_id",
           'attributes' => array('class' => array('views-ajax-link')),
         ),
+        'snapshots' => array(
+          'title' => t('snapshots'),
+          'href' => "admin/structure/views/nojs/snapshots/{$view->get('name')}",
+          'attributes' => array('class' => array('views-ajax-link')),
+        ),
       ),
     );
 
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
index 3683875..656c637 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
@@ -18,6 +18,20 @@
 abstract class ViewFormControllerBase extends EntityFormController {
 
   /**
+   * Overrides Drupal\Core\Entity\EntityFormController::getEntity().
+   */
+  public function getEntity(array $form_state) {
+    return isset($form_state['view']) ? $form_state['view'] : NULL;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::setEntity().
+   */
+  public function setEntity(EntityInterface $entity, array &$form_state) {
+    $form_state['view'] = $entity;
+  }
+
+  /**
    * Overrides Drupal\Core\Entity\EntityFormController::prepareForm().
    */
   protected function prepareEntity(EntityInterface $view) {
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotDeleteFormController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotDeleteFormController.php
new file mode 100644
index 0000000..18c0b2e
--- /dev/null
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotDeleteFormController.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\views_ui\ViewSnapshotDeleteFormController.
+ */
+
+namespace Drupal\views_ui;
+
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Form controller to delete a view snapshot.
+ */
+class ViewSnapshotDeleteFormController extends ViewFormControllerBase {
+
+  /**
+   * Overrides \Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state, EntityInterface $entity) {
+    $form = parent::form($form, $form_state, $entity);
+
+    $form_state['no_cache'] = TRUE;
+
+    $form['#section'] = $entity->id() . '-snapshot-delete';
+    $this->setEntity($entity, $form_state);
+
+    // @todo A proper label on the snapshot probably help.
+    $title = t('Are you sure you want to delete the snapshot @snapshot from @name', array(
+      '@name' => $entity->get('name'),
+      '@snapshot' => $entity->id()
+    ));
+    $form['#title'] = $title;
+
+    return confirm_form($form, $title, "admin/structure/views/view/{$entity->get('name')}/edit", t('This cannot be undone.'), t('Delete'), t('Cancel'));
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::submit().
+   */
+  public function submit(array $form, array &$form_state) {
+    $view_ui = parent::submit($form, $form_state);
+    $snapshot = $view_ui->get('storage');
+    $snapshot->delete();
+
+    drupal_set_message(t('Snapshot number @id deleted.', array('@id' => $snapshot->id())));
+
+    // @todo Redirect the user to the snapshot overview page.
+    // $form_state['redirect'] = "admin/structure/views/nojs/snapshots/{$snapshot->get('name')}";
+    // $view_ui->addFormToStack('snapshots', $view_ui->displayID, array());
+    // Store in cache.
+    // views_ui_cache_set($form_state['view']);
+  }
+
+}
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotListController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotListController.php
new file mode 100644
index 0000000..73d3a92
--- /dev/null
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotListController.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\views_ui\ViewSnapshotListController.
+ */
+
+namespace Drupal\views_ui;
+
+use Drupal\Core\Entity\EntityListController;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Provides a listing of Views.
+ */
+class ViewSnapshotListController extends EntityListController {
+
+  /**
+   * The original view object.
+   *
+   * @var Drupal\views\ViewStorage.
+   */
+  protected $original;
+
+  /**
+   * Sets the original view from which to get snapshots for.
+   *
+   * @param Drupal\Core\Entity\EntityInterface
+   */
+  public function setOriginalView(EntityInterface $original) {
+    $this->original = $original;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityListController::load();
+   */
+  public function load() {
+    $entities = $this->storage->loadByProperties(array('name' => $this->original->get('name')));
+    $this->sort($entities);
+    return $entities;
+  }
+
+  /*
+   * Helper method to sort loaded snapshots by timestamp descending.
+   */
+  protected function sort(array &$entities) {
+    uasort($entities, function ($a, $b) {
+      $a_created = $a->get('created');
+      $b_created = $b->get('created');
+      return $a_created < $b_created;
+    });
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityListController::buildRow();
+   */
+  public function buildRow(EntityInterface $view) {
+    return array(
+      'data' => array(
+        'view_snapshot_name' => $view->id(),
+        'created' => format_date($view->get('created')),
+        'comment' => check_plain($view->get('comment')),
+        'operations' => array(
+          'data' => $this->buildOperations($view),
+        ),
+      ),
+    );
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityListController::buildHeader();
+   */
+  public function buildHeader() {
+    return array(
+      'view_snapshot_name' => array(
+        'data' => t('Snapshot'),
+        'class' => array('views-ui-snapshot-name'),
+      ),
+      'created' => array(
+        'data' => t('Created'),
+        'class' => array('views-ui-snapshot-created'),
+      ),
+      'comment' => array(
+        'data' => t('Comment'),
+        'class' => array('views-ui-snapshot-comment'),
+      ),
+      'operations' => array(
+        'data' => t('Operations'),
+        'class' => array('views-ui-snapshot-operations'),
+      ),
+    );
+  }
+
+  /**
+   * Implements Drupal\Core\Entity\EntityListController::getOperations();
+   */
+  public function getOperations(EntityInterface $snapshot) {
+    $uri = $snapshot->uri();
+    $path = $uri['path'];
+
+    $definition['edit'] = array(
+      'href' => $uri['path'] . '/edit',
+      'title' => t('Edit'),
+      'weight' => -10,
+    );
+    $definition['revert'] = array(
+      'href' => "admin/structure/views/nojs/revert-snapshot/{$snapshot->id()}",
+      'title' => t('Revert'),
+      'attributes' => array('class' => 'views-ajax-link'),
+      'weight' => -5,
+    );
+    $definition['delete'] = array(
+      'href' => "admin/structure/views/nojs/delete-snapshot/{$snapshot->id()}",
+      'title' => t('Delete'),
+      'attributes' => array('class' => 'views-ajax-link'),
+      'weight' => 0,
+    );
+
+    return $definition;
+  }
+
+}
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotManageFormController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotManageFormController.php
new file mode 100644
index 0000000..7728905
--- /dev/null
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotManageFormController.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\views_ui\ViewSnapshotManageFormController.
+ */
+
+namespace Drupal\views_ui;
+
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Form controller to revert a view to a certain snapshot.
+ */
+class ViewSnapshotManageFormController extends ViewFormControllerBase {
+
+  /**
+   * Overrides \Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state, EntityInterface $entity) {
+    $form = parent::form($form, $form_state, $entity);
+
+    $list_controller = entity_list_controller('view_snapshot');
+    // Set the original view on the controller
+    $list_controller->setOriginalView($entity->get('storage'));
+
+    $form['options']['#title'] = t('View snapshots: @view', array('@view' => $entity->label()));
+    $form['#section'] = $entity->id() . '-snapshot-list';
+
+    $form['options'] = array(
+      '#theme_wrappers' => array('container'),
+      '#attributes' => array('class' => array('scroll')),
+    );
+
+    $form['options']['list'] = $list_controller->render();
+
+    $form['options']['create'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('New snapshot'),
+    );
+
+    $form['options']['create']['comment'] = array(
+      '#type' => 'textarea',
+      '#title' => t('Comment/description for the snapshot.'),
+      '#description' => t('Enter an optional comment to attach to the new snapshot when it is created.'),
+    );
+
+    $form_state['ok_button'] = TRUE;
+    $entity->getStandardButtons($form, $form_state, 'views_ui_snapshot_form', 'create_snapshot', t('Create snapshot'), 'create');
+
+    // Override the submit handler.
+    // @todo There is probably a better way but may need to modify getStandard
+    //   buttons method.
+    //$form['buttons']['create']['#submit'] = array($this, 'submit');
+
+    return $form;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::submit().
+   */
+  public function submit(array $form, array &$form_state) {
+    $snapshot_controller = entity_get_controller('view_snapshot');
+
+    $storage = $form_state['view']->get('storage');
+    $snapshot = $snapshot_controller->createSnapshot($storage, array('comment' => $form_state['values']['comment']));
+    $snapshot->save();
+
+    // Show a message and redirect to the edit view.
+    drupal_set_message(t('Snapshot number @id created.', array('@id' => $snapshot->id())));
+    $uri = $storage->uri();
+    $form_state['redirect'] = $uri['path'] . '/edit';
+  }
+
+}
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotRevertFormController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotRevertFormController.php
new file mode 100644
index 0000000..ec01138
--- /dev/null
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewSnapshotRevertFormController.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\views_ui\ViewSnapshotRevertFormController.
+ */
+
+namespace Drupal\views_ui;
+
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Form controller to revert a view to a certain snapshot.
+ */
+class ViewSnapshotRevertFormController extends ViewFormControllerBase {
+
+  /**
+   * Overrides \Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state, EntityInterface $entity) {
+    $form = parent::form($form, $form_state, $entity);
+
+    $form_state['no_cache'] = TRUE;
+
+    return confirm_form($form,
+      t('Are you sure you want to revert the view @name to the snapshot @snapshot', array('@name' => $entity->get('name'), '@snapshot' => $entity->id())),
+      "admin/structure/views/view/{$entity->get('name')}/edit",
+      t('This cannot be undone.'),
+      t('Revert'),
+      t('Cancel')
+    );
+  }
+
+  /**
+   * Overrides \Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function submit(array $form, array &$form_state) {
+    $view_ui = parent::submit($form, $form_state);
+    $snapshot = $view_ui->get('storage');
+    $view = entity_load('view', $snapshot->get('name'));
+
+    $view = entity_get_controller('view_snapshot')->revertSnapshot($view, $snapshot);
+
+    // Get the ID of the snapshot.
+    list(, $id) = explode(':', $snapshot->id(), 2);
+    drupal_set_message(t('View @name reverted to snapshot @id', array('@name' => $view->get('name'), '@id' => $id)));
+
+    // @todo The view just gets updated when you reload the browser after
+    //   reverting.
+    $view_ui = new ViewUI($view);
+    views_ui_cache_set($view_ui);
+
+    $uri = $view->uri();
+    $form_state['redirect'] = $uri['path'] . '/edit';
+  }
+
+}
diff --git a/core/modules/views/views_ui/views_ui.module b/core/modules/views/views_ui/views_ui.module
index feb6553..d592142 100644
--- a/core/modules/views/views_ui/views_ui.module
+++ b/core/modules/views/views_ui/views_ui.module
@@ -91,7 +91,8 @@ function views_ui_menu() {
     'page arguments' => array(4),
   ) + $base;
   $items['admin/structure/views/view/%views_ui_cache/edit'] = array(
-    'title' => 'Edit view',
+    'title' => '
+    Edit view',
     'type' => MENU_DEFAULT_LOCAL_TASK,
     'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
     'weight' => -10,
@@ -119,7 +120,6 @@ function views_ui_menu() {
   ) + $base;
 
   // Additional pages for acting on a View.
-
   $items['admin/structure/views/view/%views_ui_cache/break-lock'] = array(
     'title' => 'Break lock',
     'page callback' => 'drupal_get_form',
@@ -181,6 +181,8 @@ function views_ui_menu() {
     'page callback' => 'views_ui_plugin_list',
   ) + $base;
 
+//  $items['admin/structure/views']
+
   return $items;
 }
 
@@ -309,7 +311,7 @@ function views_ui_edit_page_title(ViewUI $view) {
  * Specialized menu callback to load a view and check its locked status.
  *
  * @param $name
- *   The machine name of the view.
+ *   The machine name of the view or the view snapshot.
  *
  * @return
  *   The view object, with a "locked" property indicating whether or not
@@ -318,7 +320,14 @@ function views_ui_edit_page_title(ViewUI $view) {
 function views_ui_cache_load($name) {
   $views_temp_store = drupal_container()->get('user.tempstore')->get('views');
   $view = $views_temp_store->get($name);
-  $storage = entity_load('view', $name);
+
+  if (strpos($name, ':') === FALSE) {
+    $storage = entity_load('view', $name);
+  }
+  else {
+    $storage = entity_load('view_snapshot', $name);
+  }
+
   $original_view = $storage ? new ViewUI($storage) : NULL;
 
   if (empty($view)) {
