Merge "Add option to omit duplicate comments."
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index a320a54..6920c4c 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -1256,7 +1256,7 @@
   {
     "context": 10,
     "theme": "DEFAULT",
-    "ignore_whitespace": "IGNORE_ALL_SPACE",
+    "ignore_whitespace": "IGNORE_ALL",
     "intraline_difference": true,
     "line_length": 100,
     "show_tabs": true,
@@ -1285,7 +1285,7 @@
   {
     "context": 10,
     "theme": "ECLIPSE",
-    "ignore_whitespace": "IGNORE_ALL_SPACE",
+    "ignore_whitespace": "IGNORE_ALL",
     "intraline_difference": true,
     "line_length": 100,
     "show_line_endings": true,
@@ -1309,7 +1309,7 @@
   {
     "context": 10,
     "theme": "ECLIPSE",
-    "ignore_whitespace": "IGNORE_ALL_SPACE",
+    "ignore_whitespace": "IGNORE_ALL",
     "intraline_difference": true,
     "line_length": 100,
     "show_line_endings": true,
@@ -1666,8 +1666,8 @@
 |`ignore_whitespace`           ||
 Whether whitespace changes should be ignored and if yes, which
 whitespace changes should be ignored. +
-Allowed values are `IGNORE_NONE`, `IGNORE_SPACE_AT_EOL`,
-`IGNORE_SPACE_CHANGE`, `IGNORE_ALL_SPACE`.
+Allowed values are `IGNORE_NONE`, `IGNORE_TRAILING`,
+`IGNORE_LEADING_AND_TRAILING`, `IGNORE_ALL`.
 |`intraline_difference`        |not set if `false`|
 Whether intraline differences should be highlighted.
 |`line_length`                 ||
@@ -1722,8 +1722,8 @@
 |`ignore_whitespace`           |optional|
 Whether whitespace changes should be ignored and if yes, which
 whitespace changes should be ignored. +
-Allowed values are `IGNORE_NONE`, `IGNORE_SPACE_AT_EOL`,
-`IGNORE_SPACE_CHANGE`, `IGNORE_ALL_SPACE`.
+Allowed values are `IGNORE_NONE`, `IGNORE_TRAILING`,
+`IGNORE_LEADING_AND_TRAILING`, `IGNORE_ALL`.
 |`intraline_difference`        |optional|
 Whether intraline differences should be highlighted.
 |`line_length`                 |optional|
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 16cc8e8..a9293f6 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -39,6 +39,7 @@
 import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.common.ApprovalInfo;
 import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.ChangeMessageInfo;
 import com.google.gerrit.extensions.common.LabelInfo;
 import com.google.gerrit.extensions.common.RevisionInfo;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -126,9 +127,28 @@
         .id(r.getChangeId())
         .revision(r.getCommit().name())
         .submit();
-    gApi.changes()
-        .id(r.getChangeId())
-        .revert();
+    ChangeInfo revertChange =
+        gApi.changes()
+            .id(r.getChangeId())
+            .revert().get();
+
+    // expected messages on source change:
+    // 1. Uploaded patch set 1.
+    // 2. Patch Set 1: Code-Review+2
+    // 3. Change has been successfully merged by Administrator
+    // 4. Patch Set 1: Reverted
+    List<ChangeMessageInfo> sourceMessages = new ArrayList<>(
+        gApi.changes().id(r.getChangeId()).get().messages);
+    assertThat(sourceMessages).hasSize(4);
+    String expectedMessage = String.format(
+        "Patch Set 1: Reverted\n\n" +
+        "This patchset was reverted in change: %s",
+        revertChange.changeId);
+    assertThat(sourceMessages.get(3).message).isEqualTo(expectedMessage);
+
+    assertThat(revertChange.messages).hasSize(1);
+    assertThat(revertChange.messages.iterator().next().message)
+        .isEqualTo("Uploaded patch set 1.");
   }
 
   @Test
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/DiffPreferencesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/DiffPreferencesIT.java
new file mode 100644
index 0000000..5550cb6
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/DiffPreferencesIT.java
@@ -0,0 +1,160 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.rest.account;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
+import com.google.gerrit.extensions.client.Theme;
+import com.google.gerrit.testutil.ConfigSuite;
+
+import org.apache.http.HttpStatus;
+import org.eclipse.jgit.lib.Config;
+import org.junit.Test;
+
+public class DiffPreferencesIT extends AbstractDaemonTest {
+  @ConfigSuite.Config
+  public static Config readFromGitConfig() {
+    Config cfg = new Config();
+    cfg.setBoolean("user", null, "readPrefsFromGit", true);
+    return cfg;
+  }
+
+  @Test
+  public void getDiffPreferencesOfNonExistingAccount_NotFound()
+      throws Exception {
+    assertEquals(HttpStatus.SC_NOT_FOUND,
+        adminSession.get("/accounts/non-existing/preferences.diff")
+        .getStatusCode());
+  }
+
+  @Test
+  public void getDiffPreferences() throws Exception {
+    RestResponse r = adminSession.get("/accounts/" + admin.email
+        + "/preferences.diff");
+    assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+    DiffPreferencesInfo d = DiffPreferencesInfo.defaults();
+    DiffPreferencesInfo o =
+        newGson().fromJson(r.getReader(), DiffPreferencesInfo.class);
+
+    assertThat(o.context).isEqualTo(d.context);
+    assertThat(o.tabSize).isEqualTo(d.tabSize);
+    assertThat(o.lineLength).isEqualTo(d.lineLength);
+    assertThat(o.expandAllComments).isNull();
+    assertThat(o.intralineDifference).isEqualTo(d.intralineDifference);
+    assertThat(o.manualReview).isNull();
+    assertThat(o.retainHeader).isNull();
+    assertThat(o.showLineEndings).isEqualTo(d.showLineEndings);
+    assertThat(o.showTabs).isEqualTo(d.showTabs);
+    assertThat(o.showWhitespaceErrors).isEqualTo(d.showWhitespaceErrors);
+    assertThat(o.skipDeleted).isNull();
+    assertThat(o.skipUncommented).isNull();
+    assertThat(o.syntaxHighlighting).isEqualTo(d.syntaxHighlighting);
+    assertThat(o.hideTopMenu).isNull();
+    assertThat(o.autoHideDiffTableHeader).isEqualTo(d.autoHideDiffTableHeader);
+    assertThat(o.hideLineNumbers).isNull();
+    assertThat(o.renderEntireFile).isNull();
+    assertThat(o.hideEmptyPane).isNull();
+    assertThat(o.ignoreWhitespace).isEqualTo(d.ignoreWhitespace);
+    assertThat(o.theme).isEqualTo(d.theme);
+  }
+
+  @Test
+  public void setDiffPreferences() throws Exception {
+    DiffPreferencesInfo i = DiffPreferencesInfo.defaults();
+
+    // change all default values
+    i.context *= -1;
+    i.tabSize *= -1;
+    i.lineLength *= -1;
+    i.theme = Theme.MIDNIGHT;
+    i.ignoreWhitespace = Whitespace.IGNORE_ALL;
+    i.expandAllComments ^= true;
+    i.intralineDifference ^= true;
+    i.manualReview ^= true;
+    i.retainHeader ^= true;
+    i.showLineEndings ^= true;
+    i.showTabs ^= true;
+    i.showWhitespaceErrors ^= true;
+    i.skipDeleted ^= true;
+    i.skipUncommented ^= true;
+    i.syntaxHighlighting ^= true;
+    i.hideTopMenu ^= true;
+    i.autoHideDiffTableHeader ^= true;
+    i.hideLineNumbers ^= true;
+    i.renderEntireFile ^= true;
+    i.hideEmptyPane ^= true;
+
+    RestResponse r = adminSession.put("/accounts/" + admin.email
+        + "/preferences.diff", i);
+    assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+    DiffPreferencesInfo o = newGson().fromJson(r.getReader(),
+        DiffPreferencesInfo.class);
+
+    assertThat(o.context).isEqualTo(i.context);
+    assertThat(o.tabSize).isEqualTo(i.tabSize);
+    assertThat(o.lineLength).isEqualTo(i.lineLength);
+    assertThat(o.expandAllComments).isEqualTo(i.expandAllComments);
+    assertThat(o.intralineDifference).isNull();
+    assertThat(o.manualReview).isEqualTo(i.manualReview);
+    assertThat(o.retainHeader).isEqualTo(i.retainHeader);
+    assertThat(o.showLineEndings).isNull();
+    assertThat(o.showTabs).isNull();
+    assertThat(o.showWhitespaceErrors).isNull();
+    assertThat(o.skipDeleted).isEqualTo(i.skipDeleted);
+    assertThat(o.skipUncommented).isEqualTo(i.skipUncommented);
+    assertThat(o.syntaxHighlighting).isNull();
+    assertThat(o.hideTopMenu).isEqualTo(i.hideTopMenu);
+    assertThat(o.autoHideDiffTableHeader).isNull();
+    assertThat(o.hideLineNumbers).isEqualTo(i.hideLineNumbers);
+    assertThat(o.renderEntireFile).isEqualTo(i.renderEntireFile);
+    assertThat(o.hideEmptyPane).isEqualTo(i.hideEmptyPane);
+    assertThat(o.ignoreWhitespace).isEqualTo(i.ignoreWhitespace);
+    assertThat(o.theme).isEqualTo(i.theme);
+
+    // Partially fill input record
+    i = new DiffPreferencesInfo();
+    i.tabSize = 42;
+    r = adminSession.put("/accounts/" + admin.email
+        + "/preferences.diff", i);
+    DiffPreferencesInfo a = newGson().fromJson(r.getReader(),
+        DiffPreferencesInfo.class);
+
+    assertThat(a.context).isEqualTo(o.context);
+    assertThat(a.tabSize).isEqualTo(42);
+    assertThat(a.lineLength).isEqualTo(o.lineLength);
+    assertThat(a.expandAllComments).isEqualTo(o.expandAllComments);
+    assertThat(a.intralineDifference).isNull();
+    assertThat(a.manualReview).isEqualTo(o.manualReview);
+    assertThat(a.retainHeader).isEqualTo(o.retainHeader);
+    assertThat(a.showLineEndings).isNull();
+    assertThat(a.showTabs).isNull();
+    assertThat(a.showWhitespaceErrors).isNull();
+    assertThat(a.skipDeleted).isEqualTo(o.skipDeleted);
+    assertThat(a.skipUncommented).isEqualTo(o.skipUncommented);
+    assertThat(a.syntaxHighlighting).isNull();
+    assertThat(a.hideTopMenu).isEqualTo(o.hideTopMenu);
+    assertThat(a.autoHideDiffTableHeader).isNull();
+    assertThat(a.hideLineNumbers).isEqualTo(o.hideLineNumbers);
+    assertThat(a.renderEntireFile).isEqualTo(o.renderEntireFile);
+    assertThat(a.hideEmptyPane).isEqualTo(o.hideEmptyPane);
+    assertThat(a.ignoreWhitespace).isEqualTo(o.ignoreWhitespace);
+    assertThat(a.theme).isEqualTo(o.theme);
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/EditPreferencesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/EditPreferencesIT.java
index 8770c3c..cf89c5a 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/EditPreferencesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/EditPreferencesIT.java
@@ -69,6 +69,18 @@
     assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
     EditPreferencesInfo info = getEditPrefInfo(r);
     assertEditPreferences(info, out);
+
+    // Partially filled input record
+    EditPreferencesInfo in = new EditPreferencesInfo();
+    in.tabSize = 42;
+    r = adminSession.put(endPoint, in);
+    assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
+
+    r = adminSession.get(endPoint);
+    assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+    info = getEditPrefInfo(r);
+    out.tabSize = in.tabSize;
+    assertEditPreferences(info, out);
   }
 
   private EditPreferencesInfo getEditPrefInfo(RestResponse r)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/GetDiffPreferencesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/GetDiffPreferencesIT.java
deleted file mode 100644
index 02a94f8..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/GetDiffPreferencesIT.java
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.acceptance.rest.account;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
-import com.google.gerrit.server.account.GetDiffPreferences.DiffPreferencesInfo;
-
-import org.apache.http.HttpStatus;
-import org.junit.Test;
-
-public class GetDiffPreferencesIT extends AbstractDaemonTest {
-  @Test
-  public void getDiffPreferencesOfNonExistingAccount_NotFound()
-      throws Exception {
-    assertThat(adminSession.get("/accounts/non-existing/preferences.diff").getStatusCode())
-      .isEqualTo(HttpStatus.SC_NOT_FOUND);
-  }
-
-  @Test
-  public void getDiffPreferences() throws Exception {
-    RestResponse r = adminSession.get("/accounts/" + admin.email + "/preferences.diff");
-    assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
-    DiffPreferencesInfo diffPreferences =
-        newGson().fromJson(r.getReader(), DiffPreferencesInfo.class);
-    assertDiffPreferences(new AccountDiffPreference(admin.id), diffPreferences);
-  }
-
-  private static void assertDiffPreferences(AccountDiffPreference expected, DiffPreferencesInfo actual) {
-    assertThat(actual.context).isEqualTo(expected.getContext());
-    assertThat(toBoolean(actual.expandAllComments)).isEqualTo(expected.isExpandAllComments());
-    assertThat(actual.ignoreWhitespace).isEqualTo(expected.getIgnoreWhitespace());
-    assertThat(toBoolean(actual.intralineDifference)).isEqualTo(expected.isIntralineDifference());
-    assertThat(actual.lineLength).isEqualTo(expected.getLineLength());
-    assertThat(toBoolean(actual.manualReview)).isEqualTo(expected.isManualReview());
-    assertThat(toBoolean(actual.retainHeader)).isEqualTo(expected.isRetainHeader());
-    assertThat(toBoolean(actual.showLineEndings)).isEqualTo(expected.isShowLineEndings());
-    assertThat(toBoolean(actual.showTabs)).isEqualTo(expected.isShowTabs());
-    assertThat(toBoolean(actual.showWhitespaceErrors)).isEqualTo(expected.isShowWhitespaceErrors());
-    assertThat(toBoolean(actual.skipDeleted)).isEqualTo(expected.isSkipDeleted());
-    assertThat(toBoolean(actual.skipUncommented)).isEqualTo(expected.isSkipUncommented());
-    assertThat(toBoolean(actual.syntaxHighlighting)).isEqualTo(expected.isSyntaxHighlighting());
-    assertThat(actual.tabSize).isEqualTo(expected.getTabSize());
-  }
-
-  private static boolean toBoolean(Boolean b) {
-    if (b == null) {
-      return false;
-    }
-    return b.booleanValue();
-  }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java
index b80d6d9..c4a07f2 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java
@@ -20,8 +20,8 @@
 
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.Patch.ChangeType;
 import com.google.gerrit.server.patch.PatchListCache;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountService.java
index 81bca20..533dfa2 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountService.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.common.audit.Audit;
 import com.google.gerrit.common.auth.SignInRequired;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gerrit.reviewdb.client.AccountProjectWatch;
 import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwtjsonrpc.common.RemoteJsonService;
@@ -35,7 +35,7 @@
 
   @Audit
   @SignInRequired
-  void changeDiffPreferences(AccountDiffPreference diffPref,
+  void changeDiffPreferences(DiffPreferencesInfo diffPref,
       AsyncCallback<VoidResult> callback);
 
   @SignInRequired
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java
index 5824415..6d9c2cd 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.audit.Audit;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwtjsonrpc.common.RemoteJsonService;
@@ -29,5 +29,5 @@
 
   @Audit
   void patchSetDetail2(PatchSet.Id baseId, PatchSet.Id key,
-      AccountDiffPreference diffPrefs, AsyncCallback<PatchSetDetail> callback);
+      DiffPreferencesInfo diffPrefs, AsyncCallback<PatchSetDetail> callback);
 }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
index aa86c47..2e991d9 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 
 import java.util.Date;
 import java.util.List;
@@ -22,7 +22,7 @@
 /** Data sent as part of the host page, to bootstrap the UI. */
 public class HostPageData {
   public String version;
-  public AccountDiffPreference accountDiffPref;
+  public DiffPreferencesInfo accountDiffPref;
   public String xGerritAuth;
   public Theme theme;
   public List<String> plugins;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java
index 19fcbeb..d9601f0 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.audit.Audit;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwtjsonrpc.common.AsyncCallback;
@@ -27,5 +27,5 @@
 public interface PatchDetailService extends RemoteJsonService {
   @Audit
   void patchScript(Patch.Key key, PatchSet.Id a, PatchSet.Id b,
-      AccountDiffPreference diffPrefs, AsyncCallback<PatchScript> callback);
+      DiffPreferencesInfo diffPrefs, AsyncCallback<PatchScript> callback);
 }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
index 7bab43a..f23afb1 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.common.data;
 
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.prettify.common.EditList;
 import com.google.gerrit.prettify.common.SparseFileContent;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.Patch.ChangeType;
@@ -42,7 +42,7 @@
   protected FileMode oldMode;
   protected FileMode newMode;
   protected List<String> header;
-  protected AccountDiffPreference diffPrefs;
+  protected DiffPreferencesInfo diffPrefs;
   protected SparseFileContent a;
   protected SparseFileContent b;
   protected List<Edit> edits;
@@ -62,7 +62,7 @@
 
   public PatchScript(final Change.Key ck, final ChangeType ct, final String on,
       final String nn, final FileMode om, final FileMode nm,
-      final List<String> h, final AccountDiffPreference dp,
+      final List<String> h, final DiffPreferencesInfo dp,
       final SparseFileContent ca, final SparseFileContent cb,
       final List<Edit> e, final DisplayMethod ma, final DisplayMethod mb,
       final String mta, final String mtb, final CommentDetail cd,
@@ -142,11 +142,11 @@
     return history;
   }
 
-  public AccountDiffPreference getDiffPrefs() {
+  public DiffPreferencesInfo getDiffPrefs() {
     return diffPrefs;
   }
 
-  public void setDiffPrefs(AccountDiffPreference dp) {
+  public void setDiffPrefs(DiffPreferencesInfo dp) {
     diffPrefs = dp;
   }
 
@@ -155,7 +155,7 @@
   }
 
   public boolean isIgnoreWhitespace() {
-    return diffPrefs.getIgnoreWhitespace() != Whitespace.IGNORE_NONE;
+    return diffPrefs.ignoreWhitespace != Whitespace.IGNORE_NONE;
   }
 
   public boolean hasIntralineDifference() {
@@ -171,7 +171,7 @@
   }
 
   public boolean isExpandAllComments() {
-    return diffPrefs.isExpandAllComments();
+    return diffPrefs.expandAllComments;
   }
 
   public SparseFileContent getA() {
@@ -195,8 +195,8 @@
   }
 
   public Iterable<EditList.Hunk> getHunks() {
-    int ctx = diffPrefs.getContext();
-    if (ctx == AccountDiffPreference.WHOLE_FILE_CONTEXT) {
+    int ctx = diffPrefs.context;
+    if (ctx == DiffPreferencesInfo.WHOLE_FILE_CONTEXT) {
       ctx = Math.max(a.size(), b.size());
     }
     return new EditList(edits, ctx, a.size(), b.size()).getHunks();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/DiffPreferencesInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/DiffPreferencesInfo.java
new file mode 100644
index 0000000..c488bd7
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/DiffPreferencesInfo.java
@@ -0,0 +1,87 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.extensions.client;
+
+public class DiffPreferencesInfo {
+
+  /** Default number of lines of context. */
+  public static final int DEFAULT_CONTEXT = 10;
+
+  /** Default tab size. */
+  public static final int DEFAULT_TAB_SIZE = 8;
+
+  /** Default line length. */
+  public static final int DEFAULT_LINE_LENGTH = 100;
+
+  /** Context setting to display the entire file. */
+  public static final short WHOLE_FILE_CONTEXT = -1;
+
+  /** Typical valid choices for the default context setting. */
+  public static final short[] CONTEXT_CHOICES =
+      {3, 10, 25, 50, 75, 100, WHOLE_FILE_CONTEXT};
+
+  public static enum Whitespace {
+    IGNORE_NONE,
+    IGNORE_TRAILING,
+    IGNORE_LEADING_AND_TRAILING,
+    IGNORE_ALL;
+  }
+
+  public Integer context;
+  public Integer tabSize;
+  public Integer lineLength;
+  public Boolean expandAllComments;
+  public Boolean intralineDifference;
+  public Boolean manualReview;
+  public Boolean showLineEndings;
+  public Boolean showTabs;
+  public Boolean showWhitespaceErrors;
+  public Boolean syntaxHighlighting;
+  public Boolean hideTopMenu;
+  public Boolean autoHideDiffTableHeader;
+  public Boolean hideLineNumbers;
+  public Boolean renderEntireFile;
+  public Boolean hideEmptyPane;
+  public Theme theme;
+  public Whitespace ignoreWhitespace;
+  public Boolean retainHeader;
+  public Boolean skipDeleted;
+  public Boolean skipUncommented;
+
+  public static DiffPreferencesInfo defaults() {
+    DiffPreferencesInfo i = new DiffPreferencesInfo();
+    i.context = DEFAULT_CONTEXT;
+    i.tabSize = DEFAULT_TAB_SIZE;
+    i.lineLength = DEFAULT_LINE_LENGTH;
+    i.ignoreWhitespace = Whitespace.IGNORE_NONE;
+    i.theme = Theme.DEFAULT;
+    i.expandAllComments = false;
+    i.intralineDifference = true;
+    i.manualReview = false;
+    i.retainHeader = false;
+    i.showLineEndings = true;
+    i.showTabs = true;
+    i.showWhitespaceErrors = true;
+    i.skipDeleted = false;
+    i.skipUncommented = false;
+    i.syntaxHighlighting = true;
+    i.hideTopMenu = false;
+    i.autoHideDiffTableHeader = true;
+    i.hideLineNumbers = false;
+    i.renderEntireFile = false;
+    i.hideEmptyPane = false;
+    return i;
+  }
+}
\ No newline at end of file
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
index cd53b8e..ee67116 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -47,9 +47,9 @@
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.HostPageData;
 import com.google.gerrit.common.data.SystemInfoService;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.extensions.client.EditPreferencesInfo;
 import com.google.gerrit.extensions.client.GerritTopMenu;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.aria.client.Roles;
 import com.google.gwt.core.client.EntryPoint;
@@ -119,7 +119,7 @@
   private static String docUrl;
   private static HostPageData.Theme myTheme;
   private static String defaultScreenToken;
-  private static AccountDiffPreference myAccountDiffPref;
+  private static DiffPreferencesInfo myAccountDiffPref;
   private static EditPreferencesInfo editPrefs;
   private static String xGerritAuth;
   private static boolean isNoteDbEnabled;
@@ -321,12 +321,12 @@
     return myPrefs;
   }
 
-  /** @return the currently signed in users's diff preferences; null if no diff preferences defined for the account */
-  public static AccountDiffPreference getAccountDiffPreference() {
+  /** @return the currently signed in users's diff preferences, or default values */
+  public static DiffPreferencesInfo getDiffPreferences() {
     return myAccountDiffPref;
   }
 
-  public static void setAccountDiffPreference(AccountDiffPreference accountDiffPref) {
+  public static void setDiffPreferences(DiffPreferencesInfo accountDiffPref) {
     myAccountDiffPref = accountDiffPref;
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
index 54541e4..07d45e9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
@@ -14,55 +14,58 @@
 
 package com.google.gerrit.client.account;
 
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.extensions.client.Theme;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gwt.core.client.JavaScriptObject;
 
 public class DiffPreferences extends JavaScriptObject {
-  public static DiffPreferences create(AccountDiffPreference in) {
+  public static DiffPreferences create(DiffPreferencesInfo in) {
     DiffPreferences p = createObject().cast();
-    if (in == null) {
-      in = AccountDiffPreference.createDefault(null);
-    }
-    p.ignoreWhitespace(in.getIgnoreWhitespace());
-    p.tabSize(in.getTabSize());
-    p.lineLength(in.getLineLength());
-    p.context(in.getContext());
-    p.intralineDifference(in.isIntralineDifference());
-    p.showLineEndings(in.isShowLineEndings());
-    p.showTabs(in.isShowTabs());
-    p.showWhitespaceErrors(in.isShowWhitespaceErrors());
-    p.syntaxHighlighting(in.isSyntaxHighlighting());
-    p.hideTopMenu(in.isHideTopMenu());
-    p.autoHideDiffTableHeader(in.isAutoHideDiffTableHeader());
-    p.hideLineNumbers(in.isHideLineNumbers());
-    p.expandAllComments(in.isExpandAllComments());
-    p.manualReview(in.isManualReview());
-    p.renderEntireFile(in.isRenderEntireFile());
-    p.theme(in.getTheme());
-    p.hideEmptyPane(in.isHideEmptyPane());
+    p.ignoreWhitespace(in.ignoreWhitespace);
+    p.tabSize(in.tabSize);
+    p.lineLength(in.lineLength);
+    p.context(in.context);
+    p.intralineDifference(in.intralineDifference);
+    p.showLineEndings(in.showLineEndings);
+    p.showTabs(in.showTabs);
+    p.showWhitespaceErrors(in.showWhitespaceErrors);
+    p.syntaxHighlighting(in.syntaxHighlighting);
+    p.hideTopMenu(in.hideTopMenu);
+    p.autoHideDiffTableHeader(in.autoHideDiffTableHeader);
+    p.hideLineNumbers(in.hideLineNumbers);
+    p.expandAllComments(in.expandAllComments);
+    p.manualReview(in.manualReview);
+    p.renderEntireFile(in.renderEntireFile);
+    p.theme(in.theme);
+    p.hideEmptyPane(in.hideEmptyPane);
+    p.retainHeader(in.retainHeader);
+    p.skipUncommented(in.skipUncommented);
+    p.skipDeleted(in.skipDeleted);
     return p;
   }
 
-  public final void copyTo(AccountDiffPreference p) {
-    p.setIgnoreWhitespace(ignoreWhitespace());
-    p.setTabSize(tabSize());
-    p.setLineLength(lineLength());
-    p.setContext((short)context());
-    p.setIntralineDifference(intralineDifference());
-    p.setShowLineEndings(showLineEndings());
-    p.setShowTabs(showTabs());
-    p.setShowWhitespaceErrors(showWhitespaceErrors());
-    p.setSyntaxHighlighting(syntaxHighlighting());
-    p.setHideTopMenu(hideTopMenu());
-    p.setAutoHideDiffTableHeader(autoHideDiffTableHeader());
-    p.setHideLineNumbers(hideLineNumbers());
-    p.setExpandAllComments(expandAllComments());
-    p.setManualReview(manualReview());
-    p.setRenderEntireFile(renderEntireFile());
-    p.setTheme(theme());
-    p.setHideEmptyPane(hideEmptyPane());
+  public final void copyTo(DiffPreferencesInfo p) {
+    p.context = context();
+    p.tabSize = tabSize();
+    p.lineLength = lineLength();
+    p.expandAllComments = expandAllComments();
+    p.intralineDifference = intralineDifference();
+    p.manualReview = manualReview();
+    p.retainHeader = retainHeader();
+    p.showLineEndings = showLineEndings();
+    p.showTabs = showTabs();
+    p.showWhitespaceErrors = showWhitespaceErrors();
+    p.skipDeleted = skipDeleted();
+    p.skipUncommented = skipUncommented();
+    p.syntaxHighlighting = syntaxHighlighting();
+    p.hideTopMenu = hideTopMenu();
+    p.autoHideDiffTableHeader = autoHideDiffTableHeader();
+    p.hideLineNumbers = hideLineNumbers();
+    p.renderEntireFile = renderEntireFile();
+    p.hideEmptyPane = hideEmptyPane();
+    p.theme = theme();
+    p.ignoreWhitespace = ignoreWhitespace();
   }
 
   public final void ignoreWhitespace(Whitespace i) {
@@ -122,6 +125,9 @@
   public final native void manualReview(boolean r) /*-{ this.manual_review = r }-*/;
   public final native void renderEntireFile(boolean r) /*-{ this.render_entire_file = r }-*/;
   public final native void hideEmptyPane(boolean s) /*-{ this.hide_empty_pane = s }-*/;
+  public final native void retainHeader(boolean r) /*-{ this.retain_header = r }-*/;
+  public final native void skipUncommented(boolean s) /*-{ this.skip_uncommented = s }-*/;
+  public final native void skipDeleted(boolean s) /*-{ this.skip_deleted = s }-*/;
   public final native boolean intralineDifference() /*-{ return this.intraline_difference || false }-*/;
   public final native boolean showLineEndings() /*-{ return this.show_line_endings || false }-*/;
   public final native boolean showTabs() /*-{ return this.show_tabs || false }-*/;
@@ -134,6 +140,9 @@
   public final native boolean manualReview() /*-{ return this.manual_review || false }-*/;
   public final native boolean renderEntireFile() /*-{ return this.render_entire_file || false }-*/;
   public final native boolean hideEmptyPane() /*-{ return this.hide_empty_pane || false }-*/;
+  public final native boolean retainHeader() /*-{ return this.retain_header || false }-*/;
+  public final native boolean skipUncommented() /*-{ return this.skip_uncommented || false }-*/;
+  public final native boolean skipDeleted() /*-{ return this.skip_deleted || false }-*/;
 
   private final native void setThemeRaw(String i) /*-{ this.theme = i }-*/;
   private final native void setIgnoreWhitespaceRaw(String i) /*-{ this.ignore_whitespace = i }-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyDiffPreferencesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyDiffPreferencesScreen.java
index 73d4ca0..a721441 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyDiffPreferencesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyDiffPreferencesScreen.java
@@ -25,7 +25,7 @@
     super.onInitUI();
 
     PreferencesBox pb = new PreferencesBox(null);
-    pb.set(DiffPreferences.create(Gerrit.getAccountDiffPreference()));
+    pb.set(DiffPreferences.create(Gerrit.getDiffPreferences()));
     FlowPanel p = new FlowPanel();
     p.setStyleName(pb.getStyle().dialog());
     p.add(pb);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffApi.java
index 800da91..6d795d3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffApi.java
@@ -18,7 +18,7 @@
 import com.google.gerrit.client.info.FileInfo;
 import com.google.gerrit.client.rpc.NativeMap;
 import com.google.gerrit.client.rpc.RestApi;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
@@ -69,16 +69,16 @@
     return this;
   }
 
-  public DiffApi ignoreWhitespace(AccountDiffPreference.Whitespace w) {
+  public DiffApi ignoreWhitespace(DiffPreferencesInfo.Whitespace w) {
     switch (w) {
       default:
       case IGNORE_NONE:
         return ignoreWhitespace(IgnoreWhitespace.NONE);
-      case IGNORE_SPACE_AT_EOL:
+      case IGNORE_TRAILING:
         return ignoreWhitespace(IgnoreWhitespace.TRAILING);
-      case IGNORE_SPACE_CHANGE:
+      case IGNORE_LEADING_AND_TRAILING:
         return ignoreWhitespace(IgnoreWhitespace.CHANGED);
-      case IGNORE_ALL_SPACE:
+      case IGNORE_ALL:
         return ignoreWhitespace(IgnoreWhitespace.ALL);
     }
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
index 3364490..a50768d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
@@ -16,10 +16,10 @@
 
 import static com.google.gerrit.reviewdb.client.AccountDiffPreference.DEFAULT_CONTEXT;
 import static com.google.gerrit.reviewdb.client.AccountDiffPreference.WHOLE_FILE_CONTEXT;
-import static com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace.IGNORE_ALL_SPACE;
+import static com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace.IGNORE_ALL;
+import static com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace.IGNORE_LEADING_AND_TRAILING;
 import static com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace.IGNORE_NONE;
-import static com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace.IGNORE_SPACE_AT_EOL;
-import static com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace.IGNORE_SPACE_CHANGE;
+import static com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace.IGNORE_TRAILING;
 import static com.google.gwt.event.dom.client.KeyCodes.KEY_ESCAPE;
 
 import com.google.gerrit.client.Gerrit;
@@ -29,9 +29,9 @@
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.Natives;
 import com.google.gerrit.client.ui.NpIntTextBox;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.extensions.client.Theme;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.Patch.ChangeType;
 import com.google.gwt.core.client.GWT;
@@ -503,12 +503,9 @@
     AccountApi.putDiffPreferences(prefs, new GerritCallback<DiffPreferences>() {
       @Override
       public void onSuccess(DiffPreferences result) {
-        AccountDiffPreference p = Gerrit.getAccountDiffPreference();
-        if (p == null) {
-          p = AccountDiffPreference.createDefault(Gerrit.getUserAccount().getId());
-        }
+        DiffPreferencesInfo p = Gerrit.getDiffPreferences();
         result.copyTo(p);
-        Gerrit.setAccountDiffPreference(p);
+        Gerrit.setDiffPreferences(p);
       }
     });
     if (view != null) {
@@ -546,14 +543,14 @@
         PatchUtil.C.whitespaceIGNORE_NONE(),
         IGNORE_NONE.name());
     ignoreWhitespace.addItem(
-        PatchUtil.C.whitespaceIGNORE_SPACE_AT_EOL(),
-        IGNORE_SPACE_AT_EOL.name());
+        PatchUtil.C.whitespaceIGNORE_TRAILING(),
+        IGNORE_TRAILING.name());
     ignoreWhitespace.addItem(
-        PatchUtil.C.whitespaceIGNORE_SPACE_CHANGE(),
-        IGNORE_SPACE_CHANGE.name());
+        PatchUtil.C.whitespaceIGNORE_LEADING_AND_TRAILING(),
+        IGNORE_LEADING_AND_TRAILING.name());
     ignoreWhitespace.addItem(
-        PatchUtil.C.whitespaceIGNORE_ALL_SPACE(),
-        IGNORE_ALL_SPACE.name());
+        PatchUtil.C.whitespaceIGNORE_ALL(),
+        IGNORE_ALL.name());
   }
 
   private void initMode() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
index 6ff93e4..7fc84f0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
@@ -14,7 +14,8 @@
 
 package com.google.gerrit.client.diff;
 
-import static com.google.gerrit.reviewdb.client.AccountDiffPreference.WHOLE_FILE_CONTEXT;
+import static com.google.gerrit.extensions.client.DiffPreferencesInfo.WHOLE_FILE_CONTEXT;
+
 import static java.lang.Double.POSITIVE_INFINITY;
 
 import com.google.gerrit.client.Dispatcher;
@@ -151,7 +152,7 @@
     this.startSide = startSide;
     this.startLine = startLine;
 
-    prefs = DiffPreferences.create(Gerrit.getAccountDiffPreference());
+    prefs = DiffPreferences.create(Gerrit.getDiffPreferences());
     handlers = new ArrayList<>(6);
     keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
     header = new Header(keysNavigation, base, revision, path);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipManager.java
index a344e6b..5376588 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipManager.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.client.diff.DiffInfo.Region;
 import com.google.gerrit.client.patches.SkippedLine;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gwt.core.client.JsArray;
 
 import net.codemirror.lib.CodeMirror;
@@ -39,7 +39,7 @@
   }
 
   void render(int context, DiffInfo diff) {
-    if (context == AccountDiffPreference.WHOLE_FILE_CONTEXT) {
+    if (context == DiffPreferencesInfo.WHOLE_FILE_CONTEXT) {
       return;
     }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
index 2420e7a..5b9203a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
@@ -28,11 +28,11 @@
 import com.google.gerrit.common.data.CommentDetail;
 import com.google.gerrit.common.data.PatchScript;
 import com.google.gerrit.common.data.PatchSetDetail;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.prettify.client.ClientSideFormatter;
 import com.google.gerrit.prettify.client.PrettyFormatter;
 import com.google.gerrit.prettify.client.SparseHtmlFile;
 import com.google.gerrit.prettify.common.SparseFileContent;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.PatchLineComment;
 import com.google.gerrit.reviewdb.client.PatchSet;
@@ -286,8 +286,8 @@
   }
 
   protected SparseHtmlFile getSparseHtmlFileA(PatchScript s) {
-    AccountDiffPreference dp = new AccountDiffPreference(s.getDiffPrefs());
-    dp.setShowWhitespaceErrors(false);
+    DiffPreferencesInfo dp = s.getDiffPrefs();
+    dp.showWhitespaceErrors = false;
 
     PrettyFormatter f = ClientSideFormatter.FACTORY.get();
     f.setDiffPrefs(dp);
@@ -299,7 +299,7 @@
   }
 
   protected SparseHtmlFile getSparseHtmlFileB(PatchScript s) {
-    AccountDiffPreference dp = new AccountDiffPreference(s.getDiffPrefs());
+    DiffPreferencesInfo dp = s.getDiffPrefs();
 
     SparseFileContent b = s.getB();
     PrettyFormatter f = ClientSideFormatter.FACTORY.get();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
index 39aadc3..422a4dd 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
@@ -69,9 +69,9 @@
   String commentCancelEdit();
 
   String whitespaceIGNORE_NONE();
-  String whitespaceIGNORE_SPACE_AT_EOL();
-  String whitespaceIGNORE_SPACE_CHANGE();
-  String whitespaceIGNORE_ALL_SPACE();
+  String whitespaceIGNORE_TRAILING();
+  String whitespaceIGNORE_LEADING_AND_TRAILING();
+  String whitespaceIGNORE_ALL();
 
   String previousFileHelp();
   String nextFileHelp();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
index 2f68822..aa6177b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
@@ -50,9 +50,9 @@
 commentCancelEdit = Cancel comment edit
 
 whitespaceIGNORE_NONE=None
-whitespaceIGNORE_SPACE_AT_EOL=At Line End
-whitespaceIGNORE_SPACE_CHANGE=Leading, At Line End
-whitespaceIGNORE_ALL_SPACE=All
+whitespaceIGNORE_TRAILING=At Line End
+whitespaceIGNORE_LEADING_AND_TRAILING=Leading, At Line End
+whitespaceIGNORE_ALL=All
 
 previousFileHelp = Previous file
 nextFileHelp = Next file
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
index 264e043..b7ba64b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
@@ -20,8 +20,8 @@
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
 import com.google.gerrit.client.ui.NpIntTextBox;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.NodeList;
 import com.google.gwt.dom.client.OptionElement;
@@ -156,7 +156,7 @@
   public void setEnableSmallFileFeatures(final boolean on) {
     enableSmallFileFeatures = on;
     if (enableSmallFileFeatures) {
-      syntaxHighlighting.setValue(getValue().isSyntaxHighlighting());
+      syntaxHighlighting.setValue(getValue().syntaxHighlighting);
     } else {
       syntaxHighlighting.setValue(false);
     }
@@ -181,7 +181,7 @@
   public void setEnableIntralineDifference(final boolean on) {
     enableIntralineDifference = on;
     if (enableIntralineDifference) {
-      intralineDifference.setValue(getValue().isIntralineDifference());
+      intralineDifference.setValue(getValue().intralineDifference);
     } else {
       intralineDifference.setValue(false);
     }
@@ -197,36 +197,36 @@
     syntaxHighlighting.setTitle(title);
   }
 
-  public AccountDiffPreference getValue() {
+  public DiffPreferencesInfo getValue() {
     return listenablePrefs.get();
   }
 
-  public void setValue(final AccountDiffPreference dp) {
+  public void setValue(final DiffPreferencesInfo dp) {
     listenablePrefs.set(dp);
     display();
   }
 
   protected void display() {
-    final AccountDiffPreference dp = getValue();
-    setIgnoreWhitespace(dp.getIgnoreWhitespace());
+    final DiffPreferencesInfo dp = getValue();
+    setIgnoreWhitespace(dp.ignoreWhitespace);
     if (enableSmallFileFeatures) {
-      syntaxHighlighting.setValue(dp.isSyntaxHighlighting());
+      syntaxHighlighting.setValue(dp.syntaxHighlighting);
     } else {
       syntaxHighlighting.setValue(false);
     }
-    setContext(dp.getContext());
+    setContext(dp.context);
 
-    tabWidth.setIntValue(dp.getTabSize());
-    colWidth.setIntValue(dp.getLineLength());
-    intralineDifference.setValue(dp.isIntralineDifference());
-    whitespaceErrors.setValue(dp.isShowWhitespaceErrors());
-    showLineEndings.setValue(dp.isShowLineEndings());
-    showTabs.setValue(dp.isShowTabs());
-    skipDeleted.setValue(dp.isSkipDeleted());
-    skipUncommented.setValue(dp.isSkipUncommented());
-    expandAllComments.setValue(dp.isExpandAllComments());
-    retainHeader.setValue(dp.isRetainHeader());
-    manualReview.setValue(dp.isManualReview());
+    tabWidth.setIntValue(dp.tabSize);
+    colWidth.setIntValue(dp.lineLength);
+    intralineDifference.setValue(dp.intralineDifference);
+    whitespaceErrors.setValue(dp.showWhitespaceErrors);
+    showLineEndings.setValue(dp.showLineEndings);
+    showTabs.setValue(dp.showTabs);
+    skipDeleted.setValue(dp.skipDeleted);
+    skipUncommented.setValue(dp.skipUncommented);
+    expandAllComments.setValue(dp.expandAllComments);
+    retainHeader.setValue(dp.retainHeader);
+    manualReview.setValue(dp.manualReview);
   }
 
   @UiHandler("update")
@@ -244,22 +244,21 @@
       new ErrorDialog(PatchUtil.C.illegalNumberOfColumns()).center();
       return;
     }
-
-    AccountDiffPreference dp = new AccountDiffPreference(getValue());
-    dp.setIgnoreWhitespace(getIgnoreWhitespace());
-    dp.setContext(getContext());
-    dp.setTabSize(tabWidth.getIntValue());
-    dp.setLineLength(colWidth.getIntValue());
-    dp.setSyntaxHighlighting(syntaxHighlighting.getValue());
-    dp.setIntralineDifference(intralineDifference.getValue());
-    dp.setShowWhitespaceErrors(whitespaceErrors.getValue());
-    dp.setShowLineEndings(showLineEndings.getValue());
-    dp.setShowTabs(showTabs.getValue());
-    dp.setSkipDeleted(skipDeleted.getValue());
-    dp.setSkipUncommented(skipUncommented.getValue());
-    dp.setExpandAllComments(expandAllComments.getValue());
-    dp.setRetainHeader(retainHeader.getValue());
-    dp.setManualReview(manualReview.getValue());
+    DiffPreferencesInfo dp = getValue();
+    dp.ignoreWhitespace = getIgnoreWhitespace();
+    dp.context = getContext();
+    dp.tabSize = tabWidth.getIntValue();
+    dp.lineLength = colWidth.getIntValue();
+    dp.syntaxHighlighting = syntaxHighlighting.getValue();
+    dp.intralineDifference = intralineDifference.getValue();
+    dp.showWhitespaceErrors = whitespaceErrors.getValue();
+    dp.showLineEndings = showLineEndings.getValue();
+    dp.showTabs = showTabs.getValue();
+    dp.skipDeleted = skipDeleted.getValue();
+    dp.skipUncommented = skipUncommented.getValue();
+    dp.expandAllComments = expandAllComments.getValue();
+    dp.retainHeader = retainHeader.getValue();
+    dp.manualReview = manualReview.getValue();
 
     listenablePrefs.set(dp);
   }
@@ -289,18 +288,18 @@
   private void initIgnoreWhitespace(ListBox ws) {
     ws.addItem(PatchUtil.C.whitespaceIGNORE_NONE(), //
         Whitespace.IGNORE_NONE.name());
-    ws.addItem(PatchUtil.C.whitespaceIGNORE_SPACE_AT_EOL(), //
-        Whitespace.IGNORE_SPACE_AT_EOL.name());
-    ws.addItem(PatchUtil.C.whitespaceIGNORE_SPACE_CHANGE(), //
-        Whitespace.IGNORE_SPACE_CHANGE.name());
-    ws.addItem(PatchUtil.C.whitespaceIGNORE_ALL_SPACE(), //
-        Whitespace.IGNORE_ALL_SPACE.name());
+    ws.addItem(PatchUtil.C.whitespaceIGNORE_TRAILING(), //
+        Whitespace.IGNORE_TRAILING.name());
+    ws.addItem(PatchUtil.C.whitespaceIGNORE_LEADING_AND_TRAILING(), //
+        Whitespace.IGNORE_LEADING_AND_TRAILING.name());
+    ws.addItem(PatchUtil.C.whitespaceIGNORE_ALL(), //
+        Whitespace.IGNORE_ALL.name());
   }
 
   private void initContext(ListBox context) {
-    for (final short v : AccountDiffPreference.CONTEXT_CHOICES) {
+    for (final short v : DiffPreferencesInfo.CONTEXT_CHOICES) {
       final String label;
-      if (v == AccountDiffPreference.WHOLE_FILE_CONTEXT) {
+      if (v == DiffPreferencesInfo.WHOLE_FILE_CONTEXT) {
         label = Util.C.contextWholeFile();
       } else {
         label = Util.M.lines(v);
@@ -314,7 +313,7 @@
     if (0 <= sel) {
       return Whitespace.valueOf(ignoreWhitespace.getValue(sel));
     }
-    return getValue().getIgnoreWhitespace();
+    return getValue().ignoreWhitespace;
   }
 
   private void setIgnoreWhitespace(Whitespace s) {
@@ -327,12 +326,12 @@
     ignoreWhitespace.setSelectedIndex(0);
   }
 
-  private short getContext() {
+  private int getContext() {
     final int sel = context.getSelectedIndex();
     if (0 <= sel) {
       return Short.parseShort(context.getValue(sel));
     }
-    return getValue().getContext();
+    return getValue().context;
   }
 
   private void setContext(int ctx) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTable.java
index f3bc092..d84f799 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTable.java
@@ -65,9 +65,9 @@
       new PatchValidator() {
         @Override
         public boolean isValid(Patch patch) {
-          return !((listenablePrefs.get().isSkipDeleted()
+          return !((listenablePrefs.get().skipDeleted
               && patch.getChangeType().equals(ChangeType.DELETED))
-              || (listenablePrefs.get().isSkipUncommented()
+              || (listenablePrefs.get().skipUncommented
               && patch.getCommentCount() == 0));
         }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
index 10c029f..b3617d5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
@@ -294,7 +294,7 @@
   private void appendImageDifferences(final PatchScript script,
       final SafeHtmlBuilder nc) {
     final boolean syntaxHighlighting =
-        script.getDiffPrefs().isSyntaxHighlighting();
+        script.getDiffPrefs().syntaxHighlighting;
     if (script.getDisplayMethodA() == DisplayMethod.IMG) {
       final String url = getUrlA();
       appendImageLine(nc, url, syntaxHighlighting, false);
@@ -310,7 +310,7 @@
     final SparseHtmlFile a = getSparseHtmlFileA(script);
     final SparseHtmlFile b = getSparseHtmlFileB(script);
     final boolean syntaxHighlighting =
-        script.getDiffPrefs().isSyntaxHighlighting();
+        script.getDiffPrefs().syntaxHighlighting;
     for (final EditList.Hunk hunk : script.getHunks()) {
       appendHunkHeader(nc, hunk);
       while (hunk.next()) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java
index bfa308a..e587aac 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java
@@ -31,9 +31,9 @@
 import com.google.gerrit.client.ui.Screen;
 import com.google.gerrit.common.data.PatchScript;
 import com.google.gerrit.common.data.PatchSetDetail;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.prettify.client.ClientSideFormatter;
 import com.google.gerrit.prettify.client.PrettyFactory;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.Scheduler;
@@ -125,10 +125,10 @@
     lastScript = null;
   }
 
-  private void update(AccountDiffPreference dp) {
+  private void update(DiffPreferencesInfo dp) {
     // Did the user just turn on auto-review?
-    if (!reviewedPanels.getValue() && prefs.getOld().isManualReview()
-        && !dp.isManualReview()) {
+    if (!reviewedPanels.getValue() && prefs.getOld().manualReview
+        && !dp.manualReview) {
       reviewedPanels.setValue(true);
       reviewedPanels.setReviewedByCurrentUser(true);
     }
@@ -152,25 +152,25 @@
     }
   }
 
-  private boolean canReuse(AccountDiffPreference dp, PatchScript last) {
-    if (last.getDiffPrefs().getIgnoreWhitespace() != dp.getIgnoreWhitespace()) {
+  private boolean canReuse(DiffPreferencesInfo dp, PatchScript last) {
+    if (last.getDiffPrefs().ignoreWhitespace != dp.ignoreWhitespace) {
       // Whitespace ignore setting requires server computation.
       return false;
     }
 
-    final int ctx = dp.getContext();
-    if (ctx == AccountDiffPreference.WHOLE_FILE_CONTEXT && !last.getA().isWholeFile()) {
+    final int ctx = dp.context;
+    if (ctx == DiffPreferencesInfo.WHOLE_FILE_CONTEXT
+        && !last.getA().isWholeFile()) {
       // We don't have the entire file here, so we can't render it.
       return false;
     }
 
-    if (last.getDiffPrefs().getContext() < ctx && !last.getA().isWholeFile()) {
+    if (last.getDiffPrefs().context < ctx && !last.getA().isWholeFile()) {
       // We don't have sufficient context.
       return false;
     }
 
-    if (dp.isSyntaxHighlighting()
-        && !last.getA().isWholeFile()) {
+    if (dp.syntaxHighlighting && !last.getA().isWholeFile()) {
       // We need the whole file to syntax highlight accurately.
       return false;
     }
@@ -425,15 +425,15 @@
     }
 
     if (script.isHugeFile()) {
-      AccountDiffPreference dp = script.getDiffPrefs();
-      int context = dp.getContext();
-      if (context == AccountDiffPreference.WHOLE_FILE_CONTEXT) {
+      DiffPreferencesInfo dp = script.getDiffPrefs();
+      int context = dp.context;
+      if (context == DiffPreferencesInfo.WHOLE_FILE_CONTEXT) {
         context = Short.MAX_VALUE;
       } else if (context > Short.MAX_VALUE) {
         context = Short.MAX_VALUE;
       }
-      dp.setContext((short) Math.min(context, LARGE_FILE_CONTEXT));
-      dp.setSyntaxHighlighting(false);
+      dp.context = Math.min(context, LARGE_FILE_CONTEXT);
+      dp.syntaxHighlighting = false;
       script.setDiffPrefs(dp);
     }
 
@@ -453,7 +453,7 @@
 
     if (Gerrit.isSignedIn()) {
       boolean isReviewed = false;
-      if (isFirst && !prefs.get().isManualReview()) {
+      if (isFirst && !prefs.get().manualReview) {
         isReviewed = true;
         reviewedPanels.setReviewedByCurrentUser(isReviewed);
       } else {
@@ -476,9 +476,9 @@
     super.onShowView();
     if (prefsHandler == null) {
       prefsHandler = prefs.addValueChangeHandler(
-          new ValueChangeHandler<AccountDiffPreference>() {
+          new ValueChangeHandler<DiffPreferencesInfo>() {
             @Override
-            public void onValueChange(ValueChangeEvent<AccountDiffPreference> event) {
+            public void onValueChange(ValueChangeEvent<DiffPreferencesInfo> event) {
               update(event.getValue());
             }
           });
@@ -491,7 +491,7 @@
       new ErrorDialog(PatchUtil.C.intralineTimeout()).setText(
           Gerrit.C.warnTitle()).show();
     }
-    if (topView != null && prefs.get().isRetainHeader()) {
+    if (topView != null && prefs.get().retainHeader) {
       setTopView(topView);
     }
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableAccountDiffPreference.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableAccountDiffPreference.java
index 27bc107..0c31f41 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableAccountDiffPreference.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableAccountDiffPreference.java
@@ -17,11 +17,11 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.account.Util;
 import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gwtjsonrpc.common.VoidResult;
 
 public class ListenableAccountDiffPreference
-    extends ListenableOldValue<AccountDiffPreference> {
+    extends ListenableOldValue<DiffPreferencesInfo> {
 
   public ListenableAccountDiffPreference() {
     reset();
@@ -33,7 +33,7 @@
           new GerritCallback<VoidResult>() {
         @Override
         public void onSuccess(VoidResult result) {
-          Gerrit.setAccountDiffPreference(get());
+          Gerrit.setDiffPreferences(get());
           cb.onSuccess(result);
         }
 
@@ -46,10 +46,10 @@
   }
 
   public void reset() {
-    if (Gerrit.isSignedIn() && Gerrit.getAccountDiffPreference() != null) {
-      set(Gerrit.getAccountDiffPreference());
+    if (Gerrit.isSignedIn() && Gerrit.getDiffPreferences() != null) {
+      set(Gerrit.getDiffPreferences());
     } else {
-      set(AccountDiffPreference.createDefault(null));
+      set(DiffPreferencesInfo.defaults());
     }
   }
 }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
index c1a113f..389dcc7 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
@@ -24,13 +24,18 @@
 import com.google.common.primitives.Bytes;
 import com.google.gerrit.common.Version;
 import com.google.gerrit.common.data.HostPageData;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.extensions.registration.DynamicItem;
 import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.systemstatus.MessageOfTheDay;
 import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.gerrit.httpd.HtmlDomUtil;
 import com.google.gerrit.httpd.WebSession;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.AccountResource;
+import com.google.gerrit.server.account.GetDiffPreferences;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
@@ -38,10 +43,12 @@
 import com.google.gwtexpui.server.CacheHeaders;
 import com.google.gwtjsonrpc.server.JsonServlet;
 import com.google.gwtjsonrpc.server.RPCServletUtils;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -87,6 +94,7 @@
   private final StaticServlet staticServlet;
   private final boolean isNoteDbEnabled;
   private final Integer pluginsLoadTimeout;
+  private final GetDiffPreferences getDiff;
   private volatile Page page;
 
   @Inject
@@ -100,7 +108,8 @@
       DynamicSet<MessageOfTheDay> motd,
       @GerritServerConfig Config cfg,
       StaticServlet ss,
-      NotesMigration migration)
+      NotesMigration migration,
+      GetDiffPreferences diffPref)
       throws IOException, ServletException {
     currentUser = cu;
     session = w;
@@ -113,6 +122,7 @@
     staticServlet = ss;
     isNoteDbEnabled = migration.enabled();
     pluginsLoadTimeout = getPluginsLoadTimeout(cfg);
+    getDiff = diffPref;
 
     final String pageName = "HostPage.html";
     template = HtmlDomUtil.parseFile(getClass(), pageName);
@@ -187,7 +197,7 @@
       w.write(";");
 
       w.write(HPD_ID + ".accountDiffPref=");
-      json(user.asIdentifiedUser().getAccountDiffPreference(), w);
+      json(getDiffPreferences(user.asIdentifiedUser()), w);
       w.write(";");
 
       w.write(HPD_ID + ".theme=");
@@ -220,6 +230,16 @@
     }
   }
 
+  private DiffPreferencesInfo getDiffPreferences(IdentifiedUser user) {
+    try {
+      return getDiff.apply(new AccountResource(user));
+    } catch (AuthException | OrmException | ConfigInvalidException
+        | IOException e) {
+      log.warn("Cannot query account diff preferences", e);
+    }
+    return DiffPreferencesInfo.defaults();
+  }
+
   private void plugins(StringWriter w) {
     List<String> urls = Lists.newArrayList();
     for (WebUiPlugin u : plugins) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
index 968029c..0da66bf 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
@@ -19,13 +19,17 @@
 import com.google.gerrit.common.data.AgreementInfo;
 import com.google.gerrit.common.errors.InvalidQueryException;
 import com.google.gerrit.common.errors.NoSuchEntityException;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.httpd.rpc.BaseServiceImplementation;
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gerrit.reviewdb.client.AccountProjectWatch;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.AccountResource;
+import com.google.gerrit.server.account.SetDiffPreferences;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.query.QueryParseException;
@@ -37,6 +41,9 @@
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
+
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -49,18 +56,21 @@
   private final ProjectControl.Factory projectControlFactory;
   private final AgreementInfoFactory.Factory agreementInfoFactory;
   private final ChangeQueryBuilder queryBuilder;
+  private final SetDiffPreferences setDiff;
 
   @Inject
   AccountServiceImpl(final Provider<ReviewDb> schema,
       final Provider<IdentifiedUser> identifiedUser,
       final ProjectControl.Factory projectControlFactory,
       final AgreementInfoFactory.Factory agreementInfoFactory,
-      final ChangeQueryBuilder queryBuilder) {
+      final ChangeQueryBuilder queryBuilder,
+      SetDiffPreferences setDiff) {
     super(schema, identifiedUser);
     this.currentUser = identifiedUser;
     this.projectControlFactory = projectControlFactory;
     this.agreementInfoFactory = agreementInfoFactory;
     this.queryBuilder = queryBuilder;
+    this.setDiff = setDiff;
   }
 
   @Override
@@ -74,17 +84,21 @@
   }
 
   @Override
-  public void changeDiffPreferences(final AccountDiffPreference diffPref,
+  public void changeDiffPreferences(final DiffPreferencesInfo diffPref,
       AsyncCallback<VoidResult> callback) {
     run(callback, new Action<VoidResult>(){
       @Override
       public VoidResult run(ReviewDb db) throws OrmException {
-        if (!diffPref.getAccountId().equals(getAccountId())) {
-          throw new IllegalArgumentException("diffPref.getAccountId() "
-              + diffPref.getAccountId() + " doesn't match"
-              + " the accountId of the signed in user " + getAccountId());
+        if (!getUser().isIdentifiedUser()) {
+          throw new IllegalArgumentException("Not authenticated");
         }
-        db.accountDiffPreferences().upsert(Collections.singleton(diffPref));
+        IdentifiedUser me = getUser().asIdentifiedUser();
+        try {
+          setDiff.apply(new AccountResource(me), diffPref);
+        } catch (AuthException | BadRequestException | ConfigInvalidException
+            | IOException e) {
+          throw new OrmException("Cannot save diff preferences", e);
+        }
         return VoidResult.INSTANCE;
       }
     });
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java
index d0c042c..37ca524 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.common.data.ChangeDetailService;
 import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.inject.Inject;
@@ -38,7 +38,7 @@
 
   @Override
   public void patchSetDetail2(PatchSet.Id baseId, PatchSet.Id id,
-      AccountDiffPreference diffPrefs, AsyncCallback<PatchSetDetail> callback) {
+      DiffPreferencesInfo diffPrefs, AsyncCallback<PatchSetDetail> callback) {
     patchSetDetail.create(baseId, id, diffPrefs).to(callback);
   }
 }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
index 2bf5fe4..d2dc384 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
@@ -18,11 +18,11 @@
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.common.data.PatchSetDetail;
 import com.google.gerrit.common.errors.NoSuchEntityException;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.httpd.rpc.Handler;
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.reviewdb.client.AccountPatchReview;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Patch;
@@ -67,7 +67,7 @@
     PatchSetDetailFactory create(
         @Assisted("psIdBase") @Nullable PatchSet.Id psIdBase,
         @Assisted("psIdNew") PatchSet.Id psIdNew,
-        @Nullable AccountDiffPreference diffPrefs);
+        @Nullable DiffPreferencesInfo diffPrefs);
   }
 
   private final PatchSetInfoFactory infoFactory;
@@ -81,7 +81,7 @@
   private Project.NameKey project;
   private final PatchSet.Id psIdBase;
   private final PatchSet.Id psIdNew;
-  private final AccountDiffPreference diffPrefs;
+  private final DiffPreferencesInfo diffPrefs;
   private ObjectId oldId;
   private ObjectId newId;
 
@@ -98,7 +98,7 @@
       ChangeEditUtil editUtil,
       @Assisted("psIdBase") @Nullable final PatchSet.Id psIdBase,
       @Assisted("psIdNew") final PatchSet.Id psIdNew,
-      @Assisted @Nullable final AccountDiffPreference diffPrefs) {
+      @Assisted @Nullable final DiffPreferencesInfo diffPrefs) {
     this.infoFactory = psif;
     this.db = db;
     this.patchListCache = patchListCache;
@@ -145,7 +145,7 @@
           newId = toObjectId(psIdNew);
         }
 
-        list = listFor(keyFor(diffPrefs.getIgnoreWhitespace()));
+        list = listFor(keyFor(diffPrefs.ignoreWhitespace));
       } else { // OK, means use base to compare
         list = patchListCache.get(control.getChange(), patchSet);
       }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java
index 7ff3782..f9180f7 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java
@@ -17,9 +17,9 @@
 import com.google.gerrit.common.data.PatchDetailService;
 import com.google.gerrit.common.data.PatchScript;
 import com.google.gerrit.common.errors.NoSuchEntityException;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.httpd.rpc.BaseServiceImplementation;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -48,7 +48,7 @@
 
   @Override
   public void patchScript(final Patch.Key patchKey, final PatchSet.Id psa,
-      final PatchSet.Id psb, final AccountDiffPreference dp,
+      final PatchSet.Id psb, final DiffPreferencesInfo dp,
       final AsyncCallback<PatchScript> callback) {
     if (psb == null) {
       callback.onFailure(new NoSuchEntityException());
diff --git a/gerrit-prettify/BUCK b/gerrit-prettify/BUCK
index 6728ba6..9a0136e 100644
--- a/gerrit-prettify/BUCK
+++ b/gerrit-prettify/BUCK
@@ -15,6 +15,7 @@
     '//gerrit-gwtexpui:SafeHtml',
   ],
   exported_deps = [
+    '//gerrit-extension-api:client',
     '//gerrit-patch-jgit:client',
     '//gerrit-reviewdb:client',
     '//lib:gwtjsonrpc',
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java
index cdf800c..49dc2fc 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.prettify.client;
 
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.prettify.common.SparseFileContent;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gwtexpui.safehtml.client.SafeHtml;
 import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
 
@@ -73,7 +73,7 @@
   protected SparseFileContent content;
   protected EditFilter side;
   protected List<Edit> edits;
-  protected AccountDiffPreference diffPrefs;
+  protected DiffPreferencesInfo diffPrefs;
   protected String fileName;
   protected Set<Integer> trailingEdits;
 
@@ -110,7 +110,7 @@
     edits = all;
   }
 
-  public void setDiffPrefs(AccountDiffPreference how) {
+  public void setDiffPrefs(DiffPreferencesInfo how) {
     diffPrefs = how;
   }
 
@@ -132,7 +132,7 @@
     String html = toHTML(src);
 
     html = expandTabs(html);
-    if (diffPrefs.isSyntaxHighlighting() && getFileType() != null
+    if (diffPrefs.syntaxHighlighting && getFileType() != null
         && src.isWholeFile()) {
       // The prettify parsers don't like &#39; as an entity for the
       // single quote character. Replace them all out so we don't
@@ -233,7 +233,7 @@
       cleanText(txt, pos, start);
       pos = txt.indexOf(';', start + 1) + 1;
 
-      if (diffPrefs.getLineLength() <= col) {
+      if (diffPrefs.lineLength <= col) {
         buf.append("<br />");
         col = 0;
       }
@@ -247,14 +247,14 @@
 
   private void cleanText(String txt, int pos, int end) {
     while (pos < end) {
-      int free = diffPrefs.getLineLength() - col;
+      int free = diffPrefs.lineLength - col;
       if (free <= 0) {
         // The current line is full. Throw an explicit line break
         // onto the end, and we'll continue on the next line.
         //
         buf.append("<br />");
         col = 0;
-        free = diffPrefs.getLineLength();
+        free = diffPrefs.lineLength;
       }
 
       int n = Math.min(end - pos, free);
@@ -326,7 +326,7 @@
   private String toHTML(SparseFileContent src) {
     SafeHtml html;
 
-    if (diffPrefs.isIntralineDifference()) {
+    if (diffPrefs.intralineDifference) {
       html = colorLineEdits(src);
     } else {
       SafeHtmlBuilder b = new SafeHtmlBuilder();
@@ -342,7 +342,7 @@
       html = html.replaceAll("\r([^\n])", r);
     }
 
-    if (diffPrefs.isShowWhitespaceErrors()) {
+    if (diffPrefs.showWhitespaceErrors) {
       // We need to do whitespace errors before showing tabs, because
       // these patterns rely on \t as a literal, before it expands.
       //
@@ -350,12 +350,12 @@
       html = showTrailingWhitespace(html);
     }
 
-    if (diffPrefs.isShowLineEndings()){
+    if (diffPrefs.showLineEndings){
       html = showLineEndings(html);
     }
 
-    if (diffPrefs.isShowTabs()) {
-      String t = 1 < diffPrefs.getTabSize() ? "\t" : "";
+    if (diffPrefs.showTabs) {
+      String t = 1 < diffPrefs.tabSize ? "\t" : "";
       html = html.replaceAll("\t", "<span class=\"vt\">\u00BB</span>" + t);
     }
 
@@ -528,10 +528,10 @@
   private String expandTabs(String html) {
     StringBuilder tmp = new StringBuilder();
     int i = 0;
-    if (diffPrefs.isShowTabs()) {
+    if (diffPrefs.showTabs) {
       i = 1;
     }
-    for (; i < diffPrefs.getTabSize(); i++) {
+    for (; i < diffPrefs.tabSize; i++) {
       tmp.append("&nbsp;");
     }
     return html.replaceAll("\t", tmp.toString());
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
index 3e18bc8..295239f 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
@@ -16,6 +16,7 @@
 
 import static com.google.gerrit.reviewdb.client.RefNames.REFS_USERS;
 
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.IntKey;
 
@@ -51,7 +52,7 @@
  * notifications of updates on that change, or just book-marking it for faster
  * future reference. One record per starred change.</li>
  *
- * <li>{@link AccountDiffPreference}: user's preferences for rendering side-to-side
+ * <li>{@link DiffPreferencesInfo}: user's preferences for rendering side-to-side
  * and unified diff</li>
  *
  * </ul>
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java
index 7948080..cc0cbf0 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java
@@ -32,9 +32,9 @@
 
   public static enum Whitespace implements CodedEnum {
     IGNORE_NONE('N'), //
-    IGNORE_SPACE_AT_EOL('E'), //
-    IGNORE_SPACE_CHANGE('S'), //
-    IGNORE_ALL_SPACE('A');
+    IGNORE_TRAILING('E'), //
+    IGNORE_LEADING_AND_TRAILING('S'), //
+    IGNORE_ALL('A');
 
     private final char code;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
index 961cc45..44c1f01 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
@@ -17,8 +17,8 @@
 import static com.google.gerrit.rules.StoredValue.create;
 
 import com.google.common.collect.Maps;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.PatchSetInfo;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
index 2652d48..6c80d26 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
@@ -25,6 +25,7 @@
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -38,6 +39,7 @@
 import com.google.gerrit.server.git.validators.CommitValidators;
 import com.google.gerrit.server.index.ChangeIndexer;
 import com.google.gerrit.server.mail.RevertedSender;
+import com.google.gerrit.server.notedb.ChangeUpdate;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.RefControl;
@@ -184,6 +186,8 @@
   private final GitReferenceUpdated gitRefUpdated;
   private final ChangeIndexer indexer;
   private final BatchUpdate.Factory updateFactory;
+  private final ChangeMessagesUtil changeMessagesUtil;
+  private final ChangeUpdate.Factory changeUpdateFactory;
 
   @Inject
   ChangeUtil(Provider<IdentifiedUser> user,
@@ -194,7 +198,9 @@
       GitRepositoryManager gitManager,
       GitReferenceUpdated gitRefUpdated,
       ChangeIndexer indexer,
-      BatchUpdate.Factory updateFactory) {
+      BatchUpdate.Factory updateFactory,
+      ChangeMessagesUtil changeMessagesUtil,
+      ChangeUpdate.Factory changeUpdateFactory) {
     this.user = user;
     this.db = db;
     this.queryProvider = queryProvider;
@@ -204,6 +210,8 @@
     this.gitRefUpdated = gitRefUpdated;
     this.indexer = indexer;
     this.updateFactory = updateFactory;
+    this.changeMessagesUtil = changeMessagesUtil;
+    this.changeUpdateFactory = changeUpdateFactory;
   }
 
   public Change.Id revert(ChangeControl ctl, PatchSet.Id patchSetId,
@@ -270,12 +278,22 @@
         ins = changeInserterFactory.create(
               refControl, change, revertCommit)
             .setValidatePolicy(CommitValidators.Policy.GERRIT);
+
+        ChangeMessage changeMessage = new ChangeMessage(
+            new ChangeMessage.Key(
+                patchSetId.getParentKey(), ChangeUtil.messageUUID(db.get())),
+                user.get().getAccountId(), TimeUtil.nowTs(), patchSetId);
         StringBuilder msgBuf = new StringBuilder();
         msgBuf.append("Patch Set ").append(patchSetId.get()).append(": Reverted");
         msgBuf.append("\n\n");
         msgBuf.append("This patchset was reverted in change: ")
               .append(change.getKey().get());
-        ins.setMessage(msgBuf.toString());
+        changeMessage.setMessage(msgBuf.toString());
+        ChangeUpdate update = changeUpdateFactory.create(ctl, TimeUtil.nowTs());
+        changeMessagesUtil.addChangeMessage(db.get(), update, changeMessage);
+        update.commit();
+
+        ins.setMessage("Uploaded patch set 1.");
         try (BatchUpdate bu = updateFactory.create(
             db.get(), change.getProject(), refControl.getUser(),
             change.getCreatedOn())) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
index df25042..9e5ff12 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
@@ -21,7 +21,6 @@
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.common.data.AccountInfo;
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gerrit.reviewdb.client.AccountProjectWatch;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.StarredChange;
@@ -110,14 +109,16 @@
     public IdentifiedUser create(SocketAddress remotePeer, Account.Id id) {
       return new IdentifiedUser(capabilityControlFactory, authConfig, realm,
           anonymousCowardName, canonicalUrl, accountCache, groupBackend,
-          disableReverseDnsLookup, Providers.of(remotePeer), null, id, null);
+          disableReverseDnsLookup, Providers.of(remotePeer), null,
+          id, null);
     }
 
     public CurrentUser runAs(SocketAddress remotePeer, Account.Id id,
         @Nullable CurrentUser caller) {
       return new IdentifiedUser(capabilityControlFactory, authConfig, realm,
           anonymousCowardName, canonicalUrl, accountCache, groupBackend,
-          disableReverseDnsLookup, Providers.of(remotePeer), null, id, caller);
+          disableReverseDnsLookup, Providers.of(remotePeer), null,
+          id, caller);
     }
   }
 
@@ -151,7 +152,6 @@
         final AccountCache accountCache,
         final GroupBackend groupBackend,
         @DisableReverseDnsLookup final Boolean disableReverseDnsLookup,
-
         @RemotePeer final Provider<SocketAddress> remotePeerProvider,
         final Provider<ReviewDb> dbProvider) {
       this.capabilityControlFactory = capabilityControlFactory;
@@ -162,7 +162,6 @@
       this.accountCache = accountCache;
       this.groupBackend = groupBackend;
       this.disableReverseDnsLookup = disableReverseDnsLookup;
-
       this.remotePeerProvider = remotePeerProvider;
       this.dbProvider = dbProvider;
     }
@@ -170,13 +169,15 @@
     public IdentifiedUser create(Account.Id id) {
       return new IdentifiedUser(capabilityControlFactory, authConfig, realm,
           anonymousCowardName, canonicalUrl, accountCache, groupBackend,
-          disableReverseDnsLookup, remotePeerProvider, dbProvider, id, null);
+          disableReverseDnsLookup, remotePeerProvider, dbProvider,
+          id, null);
     }
 
     public IdentifiedUser runAs(Account.Id id, CurrentUser caller) {
       return new IdentifiedUser(capabilityControlFactory, authConfig, realm,
           anonymousCowardName, canonicalUrl, accountCache, groupBackend,
-          disableReverseDnsLookup, remotePeerProvider, dbProvider, id, caller);
+          disableReverseDnsLookup, remotePeerProvider, dbProvider,
+          id, caller);
     }
   }
 
@@ -274,20 +275,6 @@
     return state().getAccount();
   }
 
-  public AccountDiffPreference getAccountDiffPreference() {
-    AccountDiffPreference diffPref;
-    try {
-      diffPref = dbProvider.get().accountDiffPreferences().get(getAccountId());
-      if (diffPref == null) {
-        diffPref = AccountDiffPreference.createDefault(getAccountId());
-      }
-    } catch (OrmException e) {
-      log.warn("Cannot query account diff preferences", e);
-      diffPref = AccountDiffPreference.createDefault(getAccountId());
-    }
-    return diffPref;
-  }
-
   public boolean hasEmailAddress(String email) {
     if (validEmails.contains(email)) {
       return true;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java
index 19aeefc..d2d6bf2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java
@@ -14,91 +14,140 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.extensions.client.Theme;
+import static com.google.gerrit.server.config.ConfigUtil.loadSection;
+
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.AccountDiffPreference;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.UserConfigSections;
+import com.google.gerrit.server.patch.PatchListKey;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Repository;
+
+import java.io.IOException;
+
 @Singleton
 public class GetDiffPreferences implements RestReadView<AccountResource> {
   private final Provider<CurrentUser> self;
   private final Provider<ReviewDb> db;
+  private final Provider<AllUsersName> allUsersName;
+  private final GitRepositoryManager gitMgr;
+  private final boolean readFromGit;
 
   @Inject
-  GetDiffPreferences(Provider<CurrentUser> self, Provider<ReviewDb> db) {
+  GetDiffPreferences(Provider<CurrentUser> self,
+      Provider<ReviewDb> db,
+      @GerritServerConfig Config cfg,
+      Provider<AllUsersName> allUsersName,
+      GitRepositoryManager gitMgr) {
     this.self = self;
     this.db = db;
+    this.allUsersName = allUsersName;
+    this.gitMgr = gitMgr;
+    readFromGit = cfg.getBoolean("user", null, "readPrefsFromGit", false);
   }
 
   @Override
   public DiffPreferencesInfo apply(AccountResource rsrc)
-      throws AuthException, OrmException {
+      throws AuthException, OrmException, ConfigInvalidException, IOException {
     if (self.get() != rsrc.getUser()
         && !self.get().getCapabilities().canAdministrateServer()) {
       throw new AuthException("restricted to administrator");
     }
 
     Account.Id userId = rsrc.getUser().getAccountId();
-    AccountDiffPreference a = db.get().accountDiffPreferences().get(userId);
-    if (a == null) {
-      a = new AccountDiffPreference(userId);
-    }
-    return DiffPreferencesInfo.parse(a);
+    return readFromGit
+        ? readFromGit(userId, gitMgr, allUsersName.get(), null)
+        : readFromDb(userId);
   }
 
-  public static class DiffPreferencesInfo {
-    static DiffPreferencesInfo parse(AccountDiffPreference p) {
-      DiffPreferencesInfo info = new DiffPreferencesInfo();
-      info.context = p.getContext();
-      info.expandAllComments = p.isExpandAllComments() ? true : null;
-      info.ignoreWhitespace = p.getIgnoreWhitespace();
-      info.intralineDifference = p.isIntralineDifference() ? true : null;
-      info.lineLength = p.getLineLength();
-      info.manualReview = p.isManualReview() ? true : null;
-      info.retainHeader = p.isRetainHeader() ? true : null;
-      info.showLineEndings = p.isShowLineEndings() ? true : null;
-      info.showTabs = p.isShowTabs() ? true : null;
-      info.showWhitespaceErrors = p.isShowWhitespaceErrors() ? true : null;
-      info.skipDeleted = p.isSkipDeleted() ? true : null;
-      info.skipUncommented = p.isSkipUncommented() ? true : null;
-      info.hideTopMenu = p.isHideTopMenu() ? true : null;
-      info.autoHideDiffTableHeader = p.isAutoHideDiffTableHeader() ? true : null;
-      info.hideLineNumbers = p.isHideLineNumbers() ? true : null;
-      info.syntaxHighlighting = p.isSyntaxHighlighting() ? true : null;
-      info.tabSize = p.getTabSize();
-      info.renderEntireFile = p.isRenderEntireFile() ? true : null;
-      info.hideEmptyPane = p.isHideEmptyPane() ? true : null;
-      info.theme = p.getTheme();
-      return info;
+  static DiffPreferencesInfo readFromGit(Account.Id id,
+      GitRepositoryManager gitMgr, AllUsersName allUsersName,
+      DiffPreferencesInfo in)
+      throws IOException, ConfigInvalidException, RepositoryNotFoundException {
+    try (Repository git = gitMgr.openRepository(allUsersName)) {
+      VersionedAccountPreferences p =
+          VersionedAccountPreferences.forUser(id);
+      p.load(git);
+      DiffPreferencesInfo prefs = new DiffPreferencesInfo();
+      loadSection(p.getConfig(), UserConfigSections.DIFF, null, prefs,
+          DiffPreferencesInfo.defaults(), in);
+      return prefs;
+    }
+  }
+
+  private DiffPreferencesInfo readFromDb(Account.Id id)
+      throws OrmException {
+    AccountDiffPreference a = db.get().accountDiffPreferences().get(id);
+    return nullify(initFromDb(a));
+  }
+
+  static DiffPreferencesInfo initFromDb(AccountDiffPreference a) {
+    DiffPreferencesInfo prefs = DiffPreferencesInfo.defaults();
+    if (a != null) {
+      prefs.context = (int)a.getContext();
+      prefs.expandAllComments = a.isExpandAllComments();
+      prefs.hideLineNumbers = a.isHideLineNumbers();
+      prefs.hideTopMenu = a.isHideTopMenu();
+      prefs.ignoreWhitespace = PatchListKey.WHITESPACE_TYPES.inverse().get(
+          a.getIgnoreWhitespace().getCode());
+      prefs.intralineDifference = a.isIntralineDifference();
+      prefs.lineLength = a.getLineLength();
+      prefs.manualReview = a.isManualReview();
+      prefs.renderEntireFile = a.isRenderEntireFile();
+      prefs.retainHeader = a.isRetainHeader();
+      prefs.showLineEndings = a.isShowLineEndings();
+      prefs.showTabs = a.isShowTabs();
+      prefs.showWhitespaceErrors = a.isShowWhitespaceErrors();
+      prefs.skipDeleted = a.isSkipDeleted();
+      prefs.skipUncommented = a.isSkipUncommented();
+      prefs.syntaxHighlighting = a.isSyntaxHighlighting();
+      prefs.tabSize = a.getTabSize();
+      prefs.theme = a.getTheme();
+      prefs.hideEmptyPane = a.isHideEmptyPane();
+      prefs.autoHideDiffTableHeader = a.isAutoHideDiffTableHeader();
     }
 
-    public short context;
-    public Boolean expandAllComments;
-    public Whitespace ignoreWhitespace;
-    public Boolean intralineDifference;
-    public int lineLength;
-    public Boolean manualReview;
-    public Boolean retainHeader;
-    public Boolean showLineEndings;
-    public Boolean showTabs;
-    public Boolean showWhitespaceErrors;
-    public Boolean skipDeleted;
-    public Boolean skipUncommented;
-    public Boolean syntaxHighlighting;
-    public Boolean hideTopMenu;
-    public Boolean autoHideDiffTableHeader;
-    public Boolean hideLineNumbers;
-    public Boolean renderEntireFile;
-    public Boolean hideEmptyPane;
-    public int tabSize;
-    public Theme theme;
+    return prefs;
+  }
+
+  private static DiffPreferencesInfo nullify(DiffPreferencesInfo prefs) {
+    prefs.expandAllComments = b(prefs.expandAllComments);
+    prefs.hideLineNumbers = b(prefs.hideLineNumbers);
+    prefs.hideTopMenu = b(prefs.hideTopMenu);
+    prefs.intralineDifference = b(prefs.intralineDifference);
+    prefs.manualReview = b(prefs.manualReview);
+    prefs.renderEntireFile = b(prefs.renderEntireFile);
+    prefs.retainHeader = b(prefs.retainHeader);
+    prefs.showLineEndings = b(prefs.showLineEndings);
+    prefs.showTabs = b(prefs.showTabs);
+    prefs.showWhitespaceErrors = b(prefs.showWhitespaceErrors);
+    prefs.skipDeleted = b(prefs.skipDeleted);
+    prefs.skipUncommented = b(prefs.skipUncommented);
+    prefs.syntaxHighlighting = b(prefs.syntaxHighlighting);
+    prefs.hideEmptyPane = b(prefs.hideEmptyPane);
+    prefs.autoHideDiffTableHeader = b(prefs.autoHideDiffTableHeader);
+    return prefs;
+  }
+
+  private static Boolean b(Boolean b) {
+    if (b == null) {
+      return null;
+    }
+    return b ? Boolean.TRUE : null;
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetEditPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetEditPreferences.java
index e6e7644..d99b68f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetEditPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetEditPreferences.java
@@ -19,6 +19,7 @@
 import com.google.gerrit.extensions.client.EditPreferencesInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.git.GitRepositoryManager;
@@ -28,6 +29,7 @@
 import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.Repository;
 
 import java.io.IOException;
@@ -55,13 +57,21 @@
       throw new AuthException("restricted to members of Modify Accounts");
     }
 
+    return readFromGit(
+        rsrc.getUser().getAccountId(), gitMgr, allUsersName, null);
+  }
+
+  static EditPreferencesInfo readFromGit(Account.Id id,
+      GitRepositoryManager gitMgr, AllUsersName allUsersName,
+      EditPreferencesInfo in) throws IOException, ConfigInvalidException,
+          RepositoryNotFoundException {
     try (Repository git = gitMgr.openRepository(allUsersName)) {
       VersionedAccountPreferences p =
-          VersionedAccountPreferences.forUser(rsrc.getUser().getAccountId());
+          VersionedAccountPreferences.forUser(id);
       p.load(git);
 
       return loadSection(p.getConfig(), UserConfigSections.EDIT, null,
-          new EditPreferencesInfo(), EditPreferencesInfo.defaults());
+          new EditPreferencesInfo(), EditPreferencesInfo.defaults(), in);
     }
   }
 }
\ No newline at end of file
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/SetDiffPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/SetDiffPreferences.java
index 4e08756..7b4d133 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/SetDiffPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/SetDiffPreferences.java
@@ -14,144 +14,224 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.extensions.client.Theme;
+import static com.google.gerrit.server.account.GetDiffPreferences.initFromDb;
+import static com.google.gerrit.server.account.GetDiffPreferences.readFromGit;
+import static com.google.gerrit.server.config.ConfigUtil.loadSection;
+import static com.google.gerrit.server.config.ConfigUtil.storeSection;
+
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.account.GetDiffPreferences.DiffPreferencesInfo;
-import com.google.gerrit.server.account.SetDiffPreferences.Input;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.UserConfigSections;
+import com.google.gerrit.server.patch.PatchListKey;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.Config;
+
+import java.io.IOException;
 import java.util.Collections;
 
 @Singleton
-public class SetDiffPreferences implements RestModifyView<AccountResource, Input> {
-  static class Input {
-    Short context;
-    Boolean expandAllComments;
-    Whitespace ignoreWhitespace;
-    Boolean intralineDifference;
-    Integer lineLength;
-    Boolean manualReview;
-    Boolean retainHeader;
-    Boolean showLineEndings;
-    Boolean showTabs;
-    Boolean showWhitespaceErrors;
-    Boolean skipDeleted;
-    Boolean skipUncommented;
-    Boolean syntaxHighlighting;
-    Boolean hideTopMenu;
-    Boolean autoHideDiffTableHeader;
-    Boolean hideLineNumbers;
-    Boolean renderEntireFile;
-    Integer tabSize;
-    Theme theme;
-    Boolean hideEmptyPane;
-  }
-
+public class SetDiffPreferences implements
+    RestModifyView<AccountResource, DiffPreferencesInfo> {
   private final Provider<CurrentUser> self;
   private final Provider<ReviewDb> db;
+  private final Provider<MetaDataUpdate.User> metaDataUpdateFactory;
+  private final AllUsersName allUsersName;
+  private final GitRepositoryManager gitMgr;
+  private final boolean readFromGit;
 
   @Inject
-  SetDiffPreferences(Provider<CurrentUser> self, Provider<ReviewDb> db) {
+  SetDiffPreferences(Provider<CurrentUser> self,
+      Provider<ReviewDb> db,
+      @GerritServerConfig Config cfg,
+      Provider<MetaDataUpdate.User> metaDataUpdateFactory,
+      AllUsersName allUsersName,
+      GitRepositoryManager gitMgr) {
     this.self = self;
     this.db = db;
+    this.metaDataUpdateFactory = metaDataUpdateFactory;
+    this.allUsersName = allUsersName;
+    this.gitMgr = gitMgr;
+    readFromGit = cfg.getBoolean("user", null, "readPrefsFromGit", false);
   }
 
   @Override
-  public DiffPreferencesInfo apply(AccountResource rsrc, Input input)
-      throws AuthException, OrmException {
+  public DiffPreferencesInfo apply(AccountResource rsrc, DiffPreferencesInfo in)
+      throws AuthException, BadRequestException, ConfigInvalidException,
+      RepositoryNotFoundException, IOException, OrmException {
     if (self.get() != rsrc.getUser()
         && !self.get().getCapabilities().canModifyAccount()) {
       throw new AuthException("restricted to members of Modify Accounts");
     }
-    if (input == null) {
-      input = new Input();
+
+    if (in == null) {
+      throw new BadRequestException("input must be provided");
     }
 
-    Account.Id accountId = rsrc.getUser().getAccountId();
-    AccountDiffPreference p;
+    Account.Id userId = rsrc.getUser().getAccountId();
+    DiffPreferencesInfo n = readFromGit
+        ? readFromGit(userId, gitMgr, allUsersName, in)
+        : merge(initFromDb(db.get().accountDiffPreferences().get(userId)), in);
+    DiffPreferencesInfo out = writeToGit(n, userId);
+    writeToDb(n, userId);
+    return out;
+  }
 
-    db.get().accounts().beginTransaction(accountId);
+  private void writeToDb(DiffPreferencesInfo in, Account.Id id)
+      throws OrmException {
+    db.get().accounts().beginTransaction(id);
     try {
-      p = db.get().accountDiffPreferences().get(accountId);
-      if (p == null) {
-        p = new AccountDiffPreference(accountId);
-      }
-
-      if (input.context != null) {
-        p.setContext(input.context);
-      }
-      if (input.ignoreWhitespace != null) {
-        p.setIgnoreWhitespace(input.ignoreWhitespace);
-      }
-      if (input.expandAllComments != null) {
-        p.setExpandAllComments(input.expandAllComments);
-      }
-      if (input.intralineDifference != null) {
-        p.setIntralineDifference(input.intralineDifference);
-      }
-      if (input.lineLength != null) {
-        p.setLineLength(input.lineLength);
-      }
-      if (input.manualReview != null) {
-        p.setManualReview(input.manualReview);
-      }
-      if (input.retainHeader != null) {
-        p.setRetainHeader(input.retainHeader);
-      }
-      if (input.showLineEndings != null) {
-        p.setShowLineEndings(input.showLineEndings);
-      }
-      if (input.showTabs != null) {
-        p.setShowTabs(input.showTabs);
-      }
-      if (input.showWhitespaceErrors != null) {
-        p.setShowWhitespaceErrors(input.showWhitespaceErrors);
-      }
-      if (input.skipDeleted != null) {
-        p.setSkipDeleted(input.skipDeleted);
-      }
-      if (input.skipUncommented != null) {
-        p.setSkipUncommented(input.skipUncommented);
-      }
-      if (input.syntaxHighlighting != null) {
-        p.setSyntaxHighlighting(input.syntaxHighlighting);
-      }
-      if (input.hideTopMenu != null) {
-        p.setHideTopMenu(input.hideTopMenu);
-      }
-      if (input.autoHideDiffTableHeader != null) {
-        p.setAutoHideDiffTableHeader(input.autoHideDiffTableHeader);
-      }
-      if (input.hideLineNumbers != null) {
-        p.setHideLineNumbers(input.hideLineNumbers);
-      }
-      if (input.renderEntireFile != null) {
-        p.setRenderEntireFile(input.renderEntireFile);
-      }
-      if (input.tabSize != null) {
-        p.setTabSize(input.tabSize);
-      }
-      if (input.theme != null) {
-        p.setTheme(input.theme);
-      }
-      if (input.hideEmptyPane != null) {
-        p.setHideEmptyPane(input.hideEmptyPane);
-      }
-
+      AccountDiffPreference p = db.get().accountDiffPreferences().get(id);
+      p = initAccountDiffPreferences(p, in, id);
       db.get().accountDiffPreferences().upsert(Collections.singleton(p));
       db.get().commit();
     } finally {
       db.get().rollback();
     }
-    return DiffPreferencesInfo.parse(p);
+  }
+
+  private DiffPreferencesInfo writeToGit(DiffPreferencesInfo in,
+      Account.Id useId) throws RepositoryNotFoundException, IOException,
+          ConfigInvalidException {
+    MetaDataUpdate md = metaDataUpdateFactory.get().create(allUsersName);
+
+    VersionedAccountPreferences prefs;
+    DiffPreferencesInfo out = new DiffPreferencesInfo();
+    try {
+      prefs = VersionedAccountPreferences.forUser(useId);
+      prefs.load(md);
+      storeSection(prefs.getConfig(), UserConfigSections.DIFF, null, in,
+          DiffPreferencesInfo.defaults());
+      prefs.commit(md);
+      loadSection(prefs.getConfig(), UserConfigSections.DIFF, null, out,
+          DiffPreferencesInfo.defaults(), null);
+    } finally {
+      md.close();
+    }
+    return out;
+  }
+
+  // TODO(davido): Remove manual merging in follow-up change
+  private DiffPreferencesInfo merge(DiffPreferencesInfo n,
+      DiffPreferencesInfo i) {
+    if (i.context != null) {
+      n.context = i.context;
+    }
+    if (i.expandAllComments != null) {
+      n.expandAllComments = i.expandAllComments;
+    }
+    if (i.hideLineNumbers != null) {
+      n.hideLineNumbers = i.hideLineNumbers;
+    }
+    if (i.hideTopMenu != null) {
+      n.hideTopMenu = i.hideTopMenu;
+    }
+    if (i.ignoreWhitespace != null) {
+      n.ignoreWhitespace = i.ignoreWhitespace;
+    }
+    if (i.intralineDifference != null) {
+      n.intralineDifference = i.intralineDifference;
+    }
+    if (i.lineLength != null) {
+      n.lineLength = i.lineLength;
+    }
+    if (i.manualReview != null) {
+      n.manualReview = i.manualReview;
+    }
+    if (i.renderEntireFile != null) {
+      n.renderEntireFile = i.renderEntireFile;
+    }
+    if (i.retainHeader != null) {
+      n.retainHeader = i.retainHeader;
+    }
+    if (i.showLineEndings != null) {
+      n.showLineEndings = i.showLineEndings;
+    }
+    if (i.showTabs != null) {
+      n.showTabs = i.showTabs;
+    }
+    if (i.showWhitespaceErrors != null) {
+      n.showWhitespaceErrors = i.showWhitespaceErrors;
+    }
+    if (i.skipDeleted != null) {
+      n.skipDeleted = i.skipDeleted;
+    }
+    if (i.skipUncommented != null) {
+      n.skipUncommented = i.skipUncommented;
+    }
+    if (i.syntaxHighlighting != null) {
+      n.syntaxHighlighting = i.syntaxHighlighting;
+    }
+    if (i.tabSize != null) {
+      n.tabSize = i.tabSize;
+    }
+    if (i.theme != null) {
+      n.theme = i.theme;
+    }
+    if (i.hideEmptyPane != null) {
+      n.hideEmptyPane = i.hideEmptyPane;
+    }
+    if (i.autoHideDiffTableHeader != null) {
+      n.autoHideDiffTableHeader = i.autoHideDiffTableHeader;
+    }
+    return n;
+  }
+
+  private static AccountDiffPreference initAccountDiffPreferences(
+      AccountDiffPreference a, DiffPreferencesInfo i, Account.Id id) {
+    if (a == null) {
+      a = AccountDiffPreference.createDefault(id);
+    }
+    int context = i.context == null
+        ? DiffPreferencesInfo.DEFAULT_CONTEXT
+        :  i.context;
+    a.setContext((short)context);
+    a.setExpandAllComments(b(i.expandAllComments));
+    a.setHideLineNumbers(b(i.hideLineNumbers));
+    a.setHideTopMenu(b(i.hideTopMenu));
+    a.setIgnoreWhitespace(i.ignoreWhitespace == null
+        ? Whitespace.IGNORE_NONE
+        : Whitespace.forCode(
+            PatchListKey.WHITESPACE_TYPES.get(i.ignoreWhitespace)));
+    a.setIntralineDifference(b(i.intralineDifference));
+    a.setLineLength(i.lineLength == null
+        ? DiffPreferencesInfo.DEFAULT_LINE_LENGTH
+        : i.lineLength);
+    a.setManualReview(b(i.manualReview));
+    a.setRenderEntireFile(b(i.renderEntireFile));
+    a.setRetainHeader(b(i.retainHeader));
+    a.setShowLineEndings(b(i.showLineEndings));
+    a.setShowTabs(b(i.showTabs));
+    a.setShowWhitespaceErrors(b(i.showWhitespaceErrors));
+    a.setSkipDeleted(b(i.skipDeleted));
+    a.setSkipUncommented(b(i.skipUncommented));
+    a.setSyntaxHighlighting(b(i.syntaxHighlighting));
+    a.setTabSize(i.tabSize == null
+        ? DiffPreferencesInfo.DEFAULT_TAB_SIZE
+        : i.tabSize);
+    a.setTheme(i.theme);
+    a.setHideEmptyPane(b(i.hideEmptyPane));
+    a.setAutoHideDiffTableHeader(b(i.autoHideDiffTableHeader));
+    return a;
+  }
+
+  private static boolean b(Boolean b) {
+    return b == null ? false : b;
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/SetEditPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/SetEditPreferences.java
index 2df1a77..eabe31d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/SetEditPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/SetEditPreferences.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.account;
 
+import static com.google.gerrit.server.account.GetEditPreferences.readFromGit;
 import static com.google.gerrit.server.config.ConfigUtil.storeSection;
 
 import com.google.gerrit.extensions.client.EditPreferencesInfo;
@@ -24,6 +25,7 @@
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.UserConfigSections;
 import com.google.inject.Inject;
@@ -41,14 +43,17 @@
 
   private final Provider<CurrentUser> self;
   private final Provider<MetaDataUpdate.User> metaDataUpdateFactory;
+  private final GitRepositoryManager gitMgr;
   private final AllUsersName allUsersName;
 
   @Inject
   SetEditPreferences(Provider<CurrentUser> self,
       Provider<MetaDataUpdate.User> metaDataUpdateFactory,
+      GitRepositoryManager gitMgr,
       AllUsersName allUsersName) {
     this.self = self;
     this.metaDataUpdateFactory = metaDataUpdateFactory;
+    this.gitMgr = gitMgr;
     this.allUsersName = allUsersName;
   }
 
@@ -72,7 +77,8 @@
     try {
       prefs = VersionedAccountPreferences.forUser(accountId);
       prefs.load(md);
-      storeSection(prefs.getConfig(), UserConfigSections.EDIT, null, in,
+      storeSection(prefs.getConfig(), UserConfigSections.EDIT, null,
+          readFromGit(accountId, gitMgr, allUsersName, in),
           EditPreferencesInfo.defaults());
       prefs.commit(md);
     } finally {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/FileInfoJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/FileInfoJson.java
index 84f8a04..71974c4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/FileInfoJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/FileInfoJson.java
@@ -16,8 +16,8 @@
 
 import com.google.common.collect.Maps;
 import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.extensions.common.FileInfo;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.PatchSet;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
index eef0533..3dcc442 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
@@ -24,6 +24,7 @@
 import com.google.common.collect.Maps;
 import com.google.gerrit.common.data.PatchScript;
 import com.google.gerrit.common.data.PatchScript.DisplayMethod;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.extensions.common.ChangeType;
 import com.google.gerrit.extensions.common.DiffInfo;
 import com.google.gerrit.extensions.common.DiffInfo.ContentEntry;
@@ -39,8 +40,6 @@
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.prettify.common.SparseFileContent;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
@@ -52,7 +51,6 @@
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
 
 import org.eclipse.jgit.diff.Edit;
 import org.eclipse.jgit.diff.ReplaceEdit;
@@ -69,6 +67,8 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
+import javax.inject.Inject;
+
 public class GetDiff implements RestReadView<FileResource> {
   private static final ImmutableMap<Patch.ChangeType, ChangeType> CHANGE_TYPE =
       Maps.immutableEnumMap(
@@ -93,7 +93,7 @@
   IgnoreWhitespace ignoreWhitespace = IgnoreWhitespace.NONE;
 
   @Option(name = "--context", handler = ContextOptionHandler.class)
-  short context = AccountDiffPreference.DEFAULT_CONTEXT;
+  int context = DiffPreferencesInfo.DEFAULT_CONTEXT;
 
   @Option(name = "--intraline")
   boolean intraline;
@@ -122,10 +122,10 @@
           resource.getRevision().getChangeResource(), IdString.fromDecoded(base));
       basePatchSet = baseResource.getPatchSet();
     }
-    AccountDiffPreference prefs = new AccountDiffPreference(new Account.Id(0));
-    prefs.setIgnoreWhitespace(ignoreWhitespace.whitespace);
-    prefs.setContext(context);
-    prefs.setIntralineDifference(intraline);
+    DiffPreferencesInfo prefs = new DiffPreferencesInfo();
+    prefs.ignoreWhitespace = ignoreWhitespace.whitespace;
+    prefs.context = context;
+    prefs.intralineDifference = intraline;
 
     try {
       PatchScriptFactory psf = patchScriptFactoryFactory.create(
@@ -135,7 +135,7 @@
           resource.getPatchKey().getParentKey(),
           prefs);
       psf.setLoadHistory(false);
-      psf.setLoadComments(context != AccountDiffPreference.WHOLE_FILE_CONTEXT);
+      psf.setLoadComments(context != DiffPreferencesInfo.WHOLE_FILE_CONTEXT);
       PatchScript ps = psf.call();
       Content content = new Content(ps);
       for (Edit edit : ps.getEdits()) {
@@ -369,14 +369,14 @@
   }
 
   enum IgnoreWhitespace {
-    NONE(AccountDiffPreference.Whitespace.IGNORE_NONE),
-    TRAILING(AccountDiffPreference.Whitespace.IGNORE_SPACE_AT_EOL),
-    CHANGED(AccountDiffPreference.Whitespace.IGNORE_SPACE_CHANGE),
-    ALL(AccountDiffPreference.Whitespace.IGNORE_ALL_SPACE);
+    NONE(DiffPreferencesInfo.Whitespace.IGNORE_NONE),
+    TRAILING(DiffPreferencesInfo.Whitespace.IGNORE_TRAILING),
+    CHANGED(DiffPreferencesInfo.Whitespace.IGNORE_LEADING_AND_TRAILING),
+    ALL(DiffPreferencesInfo.Whitespace.IGNORE_ALL);
 
-    private final AccountDiffPreference.Whitespace whitespace;
+    private final DiffPreferencesInfo.Whitespace whitespace;
 
-    private IgnoreWhitespace(AccountDiffPreference.Whitespace whitespace) {
+    private IgnoreWhitespace(DiffPreferencesInfo.Whitespace whitespace) {
       this.whitespace = whitespace;
     }
   }
@@ -393,7 +393,7 @@
       final String value = params.getParameter(0);
       short context;
       if ("all".equalsIgnoreCase(value)) {
-        context = AccountDiffPreference.WHOLE_FILE_CONTEXT;
+        context = DiffPreferencesInfo.WHOLE_FILE_CONTEXT;
       } else {
         try {
           context = Short.parseShort(value, 10);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
index 2b6ee41..be9d984 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
@@ -314,19 +314,19 @@
    * The loading is performed eagerly: all values are set.
    * <p>
    * Fields marked with final or transient modifiers are skipped.
-   * <p>
-   * Boolean fields are only set when their values are true.
    *
    * @param cfg config from which the values are loaded
    * @param section section
    * @param sub subsection
    * @param s instance of class in which the values are set
    * @param defaults instance of class with default values
+   * @param i instance to merge during the load. When present, the
+   * boolean fields are not nullified when their values are false
    * @return loaded instance
    * @throws ConfigInvalidException
    */
   public static <T> T loadSection(Config cfg, String section, String sub,
-      T s, T defaults) throws ConfigInvalidException {
+      T s, T defaults, T i) throws ConfigInvalidException {
     try {
       for (Field f : s.getClass().getDeclaredFields()) {
         if (skipField(f)) {
@@ -345,7 +345,7 @@
           f.set(s, cfg.getLong(section, sub, n, (Long) d));
         } else if (isBoolean(t)) {
           boolean b = cfg.getBoolean(section, sub, n, (Boolean) d);
-          if (b) {
+          if (b || i != null) {
             f.set(s, b);
           }
         } else if (t.isEnum()) {
@@ -353,6 +353,12 @@
         } else {
           throw new ConfigInvalidException("type is unknown: " + t.getName());
         }
+        if (i != null) {
+          Object o = f.get(i);
+          if (o != null) {
+            f.set(s, o);
+          }
+        }
       }
     } catch (SecurityException | IllegalArgumentException
         | IllegalAccessException e) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/UserConfigSections.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/UserConfigSections.java
index 29b5373..a1c5b8a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/UserConfigSections.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/UserConfigSections.java
@@ -22,6 +22,9 @@
   /** The edit user preferences. */
   public static final String EDIT = "edit";
 
+  /** The diff user preferences. */
+  public static final String DIFF = "diff";
+
   private UserConfigSections() {
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
index 2c4f30c..da1e7b5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
@@ -16,7 +16,7 @@
 package com.google.gerrit.server.patch;
 
 import com.google.common.cache.Cache;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
index 6f957da..15277b2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
@@ -14,15 +14,16 @@
 
 package com.google.gerrit.server.patch;
 
-import static com.google.gerrit.server.ioutil.BasicSerialization.readEnum;
-import static com.google.gerrit.server.ioutil.BasicSerialization.writeEnum;
+import static com.google.common.base.Preconditions.checkState;
 import static org.eclipse.jgit.lib.ObjectIdSerialization.readCanBeNull;
 import static org.eclipse.jgit.lib.ObjectIdSerialization.readNotNull;
 import static org.eclipse.jgit.lib.ObjectIdSerialization.writeCanBeNull;
 import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;
 
+import com.google.common.collect.BiMap;
+import com.google.common.collect.ImmutableBiMap;
 import com.google.gerrit.common.Nullable;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.ObjectId;
@@ -35,6 +36,16 @@
 public class PatchListKey implements Serializable {
   static final long serialVersionUID = 18L;
 
+  public static final BiMap<Whitespace, Character> WHITESPACE_TYPES = ImmutableBiMap.of(
+      Whitespace.IGNORE_NONE, 'N',
+      Whitespace.IGNORE_TRAILING, 'E',
+      Whitespace.IGNORE_LEADING_AND_TRAILING, 'S',
+      Whitespace.IGNORE_ALL, 'A');
+
+  static {
+    checkState(WHITESPACE_TYPES.size() == Whitespace.values().length);
+  }
+
   private transient ObjectId oldId;
   private transient ObjectId newId;
   private transient Whitespace whitespace;
@@ -108,12 +119,20 @@
   private void writeObject(final ObjectOutputStream out) throws IOException {
     writeCanBeNull(out, oldId);
     writeNotNull(out, newId);
-    writeEnum(out, whitespace);
+    Character c = WHITESPACE_TYPES.get(whitespace);
+    if (c == null) {
+      throw new IOException("Invalid whitespace type: " + whitespace);
+    }
+    out.writeChar(c);
   }
 
   private void readObject(final ObjectInputStream in) throws IOException {
     oldId = readCanBeNull(in);
     newId = readNotNull(in);
-    whitespace = readEnum(in, Whitespace.values());
+    char t = in.readChar();
+    whitespace = WHITESPACE_TYPES.inverse().get(t);
+    if (whitespace == null) {
+      throw new IOException("Invalid whitespace type code: " + t);
+    }
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
index 0e421db..aa2a8a8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
@@ -21,7 +21,7 @@
 import com.google.common.base.Function;
 import com.google.common.base.Throwables;
 import com.google.common.collect.FluentIterable;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
@@ -129,13 +129,13 @@
 
   private static RawTextComparator comparatorFor(Whitespace ws) {
     switch (ws) {
-      case IGNORE_ALL_SPACE:
+      case IGNORE_ALL:
         return RawTextComparator.WS_IGNORE_ALL;
 
-      case IGNORE_SPACE_AT_EOL:
+      case IGNORE_TRAILING:
         return RawTextComparator.WS_IGNORE_TRAILING;
 
-      case IGNORE_SPACE_CHANGE:
+      case IGNORE_LEADING_AND_TRAILING:
         return RawTextComparator.WS_IGNORE_CHANGE;
 
       case IGNORE_NONE:
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
index ff4496f..d0c3d09 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
@@ -17,10 +17,10 @@
 import com.google.gerrit.common.data.CommentDetail;
 import com.google.gerrit.common.data.PatchScript;
 import com.google.gerrit.common.data.PatchScript.DisplayMethod;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.prettify.common.EditList;
 import com.google.gerrit.prettify.common.SparseFileContent;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.PatchLineComment;
@@ -65,7 +65,7 @@
   private Project.NameKey projectKey;
   private ObjectReader reader;
   private Change change;
-  private AccountDiffPreference diffPrefs;
+  private DiffPreferencesInfo diffPrefs;
   private boolean againstParent;
   private ObjectId aId;
   private ObjectId bId;
@@ -95,11 +95,11 @@
     this.change = c;
   }
 
-  void setDiffPrefs(final AccountDiffPreference dp) {
+  void setDiffPrefs(final DiffPreferencesInfo dp) {
     diffPrefs = dp;
 
-    context = diffPrefs.getContext();
-    if (context == AccountDiffPreference.WHOLE_FILE_CONTEXT) {
+    context = diffPrefs.context;
+    if (context == DiffPreferencesInfo.WHOLE_FILE_CONTEXT) {
       context = MAX_CONTEXT;
     } else if (context > MAX_CONTEXT) {
       context = MAX_CONTEXT;
@@ -140,12 +140,12 @@
 
     if (!isModify(content)) {
       intralineDifferenceIsPossible = false;
-    } else if (diffPrefs.isIntralineDifference()) {
+    } else if (diffPrefs.intralineDifference) {
       IntraLineDiff d =
           patchListCache.getIntraLineDiff(
               new IntraLineDiffKey(
                 a.id, b.id,
-                diffPrefs.getIgnoreWhitespace() != Whitespace.IGNORE_NONE),
+                diffPrefs.ignoreWhitespace != Whitespace.IGNORE_NONE),
               IntraLineDiffArgs.create(
                 a.src, b.src, edits, projectKey, bId, b.path));
       if (d != null) {
@@ -208,7 +208,7 @@
       //
       context = MAX_CONTEXT;
 
-      packContent(diffPrefs.getIgnoreWhitespace() != Whitespace.IGNORE_NONE);
+      packContent(diffPrefs.ignoreWhitespace != Whitespace.IGNORE_NONE);
     }
 
     return new PatchScript(change.getKey(), content.getChangeType(),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
index 2169671..5836df5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
@@ -18,10 +18,10 @@
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.common.data.CommentDetail;
 import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference;
-import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.Patch.ChangeType;
@@ -66,7 +66,7 @@
         String fileName,
         @Assisted("patchSetA") PatchSet.Id patchSetA,
         @Assisted("patchSetB") PatchSet.Id patchSetB,
-        AccountDiffPreference diffPrefs);
+        DiffPreferencesInfo diffPrefs);
   }
 
   private static final Logger log =
@@ -83,7 +83,7 @@
   @Nullable
   private final PatchSet.Id psa;
   private final PatchSet.Id psb;
-  private final AccountDiffPreference diffPrefs;
+  private final DiffPreferencesInfo diffPrefs;
   private final ChangeEditUtil editReader;
   private Optional<ChangeEdit> edit;
 
@@ -110,7 +110,7 @@
       @Assisted final String fileName,
       @Assisted("patchSetA") @Nullable final PatchSet.Id patchSetA,
       @Assisted("patchSetB") final PatchSet.Id patchSetB,
-      @Assisted final AccountDiffPreference diffPrefs) {
+      @Assisted DiffPreferencesInfo diffPrefs) {
     this.repoManager = grm;
     this.builderFactory = builderFactory;
     this.patchListCache = patchListCache;
@@ -156,7 +156,7 @@
 
     try (Repository git = repoManager.openRepository(project)) {
       try {
-        final PatchList list = listFor(keyFor(diffPrefs.getIgnoreWhitespace()));
+        final PatchList list = listFor(keyFor(diffPrefs.ignoreWhitespace));
         final PatchScriptBuilder b = newBuilder(list, git);
         final PatchListEntry content = list.get(fileName);
 
@@ -192,11 +192,10 @@
   }
 
   private PatchScriptBuilder newBuilder(final PatchList list, Repository git) {
-    final AccountDiffPreference dp = new AccountDiffPreference(diffPrefs);
     final PatchScriptBuilder b = builderFactory.get();
     b.setRepository(git, project);
     b.setChange(change);
-    b.setDiffPrefs(dp);
+    b.setDiffPrefs(diffPrefs);
     b.setTrees(list.isAgainstParent(), list.getOldId(), list.getNewId());
     return b;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
index 8da9e2a..148d1df 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
@@ -19,6 +19,7 @@
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.git.GitRepositoryManager;
@@ -76,6 +77,7 @@
         for (Class<?> c : new Class<?>[] {
             AllProjectsName.class,
             AllUsersCreator.class,
+            AllUsersName.class,
             GitRepositoryManager.class,
             SitePaths.class,
             }) {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java
index ab00ba8..4f409d1 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java
@@ -98,7 +98,7 @@
     assertThat(cfg.getString(SECT, SUB, "sd")).isNull();
 
     SectionInfo out = new SectionInfo();
-    ConfigUtil.loadSection(cfg, SECT, SUB, out, d);
+    ConfigUtil.loadSection(cfg, SECT, SUB, out, d, null);
     assertThat(out.i).isEqualTo(in.i);
     assertThat(out.ii).isEqualTo(in.ii);
     assertThat(out.id).isEqualTo(d.id);
@@ -115,6 +115,25 @@
   }
 
   @Test
+  public void mergeSection() throws Exception {
+    SectionInfo d = SectionInfo.defaults();
+    Config cfg = new Config();
+    ConfigUtil.storeSection(cfg, SECT, SUB, d, d);
+
+    SectionInfo in = new SectionInfo();
+    in.i = 42;
+
+    SectionInfo out = new SectionInfo();
+    ConfigUtil.loadSection(cfg, SECT, SUB, out, d, in);
+    // Check original values preserved
+    assertThat(out.id).isEqualTo(d.id);
+    // Check merged values
+    assertThat(out.i).isEqualTo(in.i);
+    // Check that boolean attribute not nullified
+    assertThat(out.bb).isFalse();
+  }
+
+  @Test
   public void testTimeUnit() {
     assertEquals(ms(0, MILLISECONDS), parse("0"));
     assertEquals(ms(2, MILLISECONDS), parse("2ms"));