diff --git includes/common.inc includes/common.inc
index f1b1537..1d1437e 100644
--- includes/common.inc
+++ includes/common.inc
@@ -7329,6 +7329,28 @@ function entity_get_controller($entity_type) {
 }
 
 /**
+ * Loads the unchanged, i.e. not modified, entity from the database.
+ *
+ * Unlike entity_load() this function ensures the entity is directly loaded from
+ * the database, thus bypassing any static cache. In particular, this function
+ * is useful in 'presave' hooks to determine changes by comparing the entity
+ * being saved and the unchanged version.
+ *
+ * @param $entity_type
+ *   The entity type to load, e.g. node or user.
+ * @param $id
+ *   The id of the entity to load.
+ *
+ * @return
+ *   The unchanged entity, or FALSE if the entity cannot be loaded.
+ */
+function entity_load_unchanged($entity_type, $id) {
+  entity_get_controller($entity_type)->resetCache($id);
+  $result = entity_get_controller($entity_type)->load(array($id));
+  return reset($result);
+}
+
+/**
  * Invoke hook_entity_prepare_view().
  *
  * If adding a new entity similar to nodes, comments or users, you should
diff --git includes/entity.inc includes/entity.inc
index 1c3e749..9ea0084 100644
--- includes/entity.inc
+++ includes/entity.inc
@@ -24,8 +24,12 @@ interface DrupalEntityControllerInterface {
 
   /**
    * Resets the internal, static entity cache.
+   *
+   * @param $id
+   *   (optional) If specified, the cache is only reset for the entity with
+   *   the given id.
    */
-  public function resetCache();
+  public function resetCache($id = NULL);
 
   /**
    * Loads one or more entities.
@@ -139,8 +143,13 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
   /**
    * Implements DrupalEntityControllerInterface::resetCache().
    */
-  public function resetCache() {
-    $this->entityCache = array();
+  public function resetCache($id = NULL) {
+    if (isset($id)) {
+      unset($this->entityCache[$id]);
+    }
+    else {
+      $this->entityCache = array();
+    }
   }
 
   /**
diff --git modules/node/node.test modules/node/node.test
index df189bc..9f2702f 100644
--- modules/node/node.test
+++ modules/node/node.test
@@ -997,14 +997,14 @@ class NodeSaveTestCase extends DrupalWebTestCase {
     $changed = $node->changed;
 
     node_save($node);
-    $node = $this->drupalGetNodeByTitle($edit['title']);
+    $node = $this->drupalGetNodeByTitle($edit['title'], TRUE);
     $this->assertEqual($node->created, $created, t('Updating a node preserves "created" timestamp.'));
 
     // Programmatically set the timestamps using hook_node_presave.
     $node->title = 'testing_node_presave';
 
     node_save($node);
-    $node = $this->drupalGetNodeByTitle('testing_node_presave');
+    $node = $this->drupalGetNodeByTitle('testing_node_presave', TRUE);
     $this->assertEqual($node->created, 280299600, t('Saving a node uses "created" timestamp set in presave hook.'));
     $this->assertEqual($node->changed, 979534800, t('Saving a node uses "changed" timestamp set in presave hook.'));
 
@@ -1027,10 +1027,35 @@ class NodeSaveTestCase extends DrupalWebTestCase {
     $node->changed = 280299600;
 
     node_save($node);
-    $node = $this->drupalGetNodeByTitle($edit['title']);
+    $node = $this->drupalGetNodeByTitle($edit['title'], TRUE);
     $this->assertEqual($node->created, 979534800, t('Updating a node uses user-set "created" timestamp.'));
     $this->assertNotEqual($node->changed, 280299600, t('Updating a node doesn\'t use user-set "changed" timestamp.'));
   }
+
+  /**
+   * Tests determing changes in hook_node_presave().
+   */
+  function testDeterminingChanges() {
+    // Initial creation.
+    $node = (object) array(
+      'uid' => $this->web_user->uid,
+      'type' => 'article',
+      'title' => 'test_changes',
+    );
+    node_save($node);
+
+    // Update the node without applying changes.
+    node_save($node);
+    $this->assertEqual($node->title, 'test_changes', 'No changes have been determined.');
+
+    // Apply changes.
+    $node->title = 'updated';
+    node_save($node);
+
+    // The hook implementation node_test_node_presave() has to determine the
+    // changes and set the title to 'changed'.
+    $this->assertEqual($node->title, 'changed', 'Changes have been determined.');
+  }
 }
 
 /**
diff --git modules/node/tests/node_test.module modules/node/tests/node_test.module
index cfc503d..fc0c8a5 100644
--- modules/node/tests/node_test.module
+++ modules/node/tests/node_test.module
@@ -115,4 +115,10 @@ function node_test_node_presave($node) {
     // Drupal 1.0 release.
     $node->changed = 979534800;
   }
+  // Determine changes.
+  if (!empty($node->nid) && $unchanged_node = entity_load_unchanged('node', $node->nid)) {
+    if ($unchanged_node->title == 'test_changes' && $unchanged_node->title != $node->title) {
+      $node->title = 'changed';
+    }
+  }
 }
diff --git modules/simpletest/drupal_web_test_case.php modules/simpletest/drupal_web_test_case.php
index 1949b99..1f47ade 100644
--- modules/simpletest/drupal_web_test_case.php
+++ modules/simpletest/drupal_web_test_case.php
@@ -787,12 +787,14 @@ class DrupalWebTestCase extends DrupalTestCase {
    *
    * @param title
    *   A node title, usually generated by $this->randomName().
+   * @param $reset
+   *   (optional) Whether to reset the internal node_load() cache.
    *
    * @return
    *   A node object matching $title.
    */
-  function drupalGetNodeByTitle($title) {
-    $nodes = node_load_multiple(array(), array('title' => $title));
+  function drupalGetNodeByTitle($title, $reset = FALSE) {
+    $nodes = node_load_multiple(array(), array('title' => $title), $reset);
     // Load the first node returned from the database.
     $returned_node = reset($nodes);
     return $returned_node;
