Merge changes I51f888f8,I751f63ac,Ie3097ae4

* changes:
  ChangeScreen: Update token when 'Diff Against' selection is changed
  ChangeScreen: Keep 'Auto Merge' selected when navigating to diff and back
  Refactor: Add a new class to represent an object that can be diffed
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ChangeInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ChangeInfo.java
index 2644304..ff060b8 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ChangeInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ChangeInfo.java
@@ -415,6 +415,10 @@
       return PatchSet.Id.toId(_number());
     }
 
+    public final boolean isMerge() {
+      return commit().parents().length() > 1;
+    }
+
     protected RevisionInfo () {
     }
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/DiffObject.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/DiffObject.java
new file mode 100644
index 0000000..0a1aadd
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/DiffObject.java
@@ -0,0 +1,198 @@
+// Copyright (C) 2016 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.client;
+
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo.DefaultBase;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+
+/**
+ * Represent an object that can be diffed. This can be either a regular patch
+ * set, the base of a patch set, the parent of a merge, the auto-merge of a
+ * merge or an edit patch set.
+ */
+public class DiffObject {
+  public static final String AUTO_MERGE = "AutoMerge";
+
+  /**
+   * Parses a string that represents a diff object.
+   * <p>
+   * The following string representations are supported:
+   * <ul>
+   * <li>a positive integer: represents a patch set
+   * <li>a negative integer: represents a parent of a merge patch set
+   * <li>'0': represents the edit patch set
+   * <li>empty string or null: represents the parent of a 1-parent patch set,
+   * also called base
+   * <li>'AutoMerge': represents the auto-merge of a merge patch set
+   * </ul>
+   *
+   * @param changeId the ID of the change to which the diff object belongs
+   * @param str the string representation of the diff object
+   * @return the parsed diff object, {@code null} if str cannot be parsed as
+   *         diff object
+   */
+  public static DiffObject parse(Change.Id changeId, String str) {
+    if (str == null || str.isEmpty()) {
+      return new DiffObject(false);
+    }
+
+    if (AUTO_MERGE.equals(str)) {
+      return new DiffObject(true);
+    }
+
+    try {
+      return new DiffObject(new PatchSet.Id(changeId, Integer.parseInt(str)));
+    } catch (NumberFormatException e) {
+      return null;
+    }
+  }
+
+  /**
+   * Create a DiffObject that represents the parent of a 1-parent patch set.
+   */
+  public static DiffObject base() {
+    return new DiffObject(false);
+  }
+
+  /**
+   * Create a DiffObject that represents the auto-merge for a merge patch set.
+   */
+  public static DiffObject autoMerge() {
+    return new DiffObject(true);
+  }
+
+  /**
+   * Create a DiffObject that represents a patch set.
+   */
+  public static DiffObject patchSet(PatchSet.Id psId) {
+    return new DiffObject(psId);
+  }
+
+  private final PatchSet.Id psId;
+  private final boolean autoMerge;
+
+  private DiffObject(PatchSet.Id psId) {
+    this.psId = psId;
+    this.autoMerge = false;
+  }
+
+  private DiffObject(boolean autoMerge) {
+    this.psId = null;
+    this.autoMerge = autoMerge;
+  }
+
+  public boolean isBase() {
+    return psId == null && !autoMerge;
+  }
+
+  public boolean isAutoMerge() {
+    return psId == null && autoMerge;
+  }
+
+  public boolean isBaseOrAutoMerge() {
+    return psId == null;
+  }
+
+  public boolean isPatchSet() {
+    return psId != null && psId.get() > 0;
+  }
+
+  public boolean isParent() {
+    return psId != null && psId.get() < 0;
+  }
+
+  public boolean isEdit() {
+    return psId != null && psId.get() == 0;
+  }
+
+  /**
+   * Returns the DiffObject as PatchSet.Id.
+   *
+   * @return PatchSet.Id with an id > 0 for a regular patch set; PatchSet.Id
+   *         with an id < 0 for a parent of a merge; PatchSet.Id with id == 0
+   *         for an edit patch set; {@code null} for the base of a 1-parent
+   *         patch set and for the auto-merge of a merge patch set
+   */
+  public PatchSet.Id asPatchSetId() {
+    return psId;
+  }
+
+  /**
+   * Returns the parent number for a parent of a merge.
+   *
+   * @return 1-based parent number, 0 if this DiffObject is not a parent of a
+   *         merge
+   */
+  public int getParentNum() {
+    if (!isParent()) {
+      return 0;
+    }
+
+    return -psId.get();
+  }
+
+  /**
+   * Returns a string representation of this DiffObject that can be used in
+   * URLs.
+   * <p>
+   * The following string representations are returned:
+   * <ul>
+   * <li>a positive integer for a patch set
+   * <li>a negative integer for a parent of a merge patch set
+   * <li>'0' for the edit patch set
+   * <li>{@code null} for the parent of a 1-parent patch set, also called base
+   * <li>'AutoMerge' for the auto-merge of a merge patch set
+   * </ul>
+   *
+   * @return string representation of this DiffObject
+   */
+  public String asString() {
+    if (autoMerge) {
+      if (Gerrit.getUserPreferences()
+          .defaultBaseForMerges() != DefaultBase.AUTO_MERGE) {
+        return AUTO_MERGE;
+      }
+      return null;
+    }
+
+    if (psId != null) {
+      return psId.getId();
+    }
+
+    return null;
+  }
+
+  @Override
+  public String toString() {
+    if (isPatchSet()) {
+      return "Patch Set " + psId.getId();
+    }
+
+    if (isParent()) {
+      return "Parent " + psId.getId();
+    }
+
+    if (isEdit()) {
+      return "Edit Patch Set";
+    }
+
+    if (isAutoMerge()) {
+      return "Auto Merge";
+    }
+
+    return "Base";
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
index cb2ac07..e2aba0a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
@@ -108,35 +108,35 @@
 import com.google.gwtorm.client.KeyUtil;
 
 public class Dispatcher {
-  public static String toPatch(PatchSet.Id diffBase,
+  public static String toPatch(DiffObject diffBase,
       PatchSet.Id revision, String fileName) {
     return toPatch("", diffBase, revision, fileName, null, 0);
   }
 
-  public static String toPatch(PatchSet.Id diffBase,
+  public static String toPatch(DiffObject diffBase,
       PatchSet.Id revision, String fileName, DisplaySide side, int line) {
     return toPatch("", diffBase, revision, fileName, side, line);
   }
 
-  public static String toSideBySide(PatchSet.Id diffBase, Patch.Key id) {
+  public static String toSideBySide(DiffObject diffBase, Patch.Key id) {
     return toPatch("sidebyside", diffBase, id);
   }
 
-  public static String toSideBySide(PatchSet.Id diffBase,
-      PatchSet.Id revision, String fileName) {
+  public static String toSideBySide(DiffObject diffBase, PatchSet.Id revision,
+      String fileName) {
     return toPatch("sidebyside", diffBase, revision, fileName, null, 0);
   }
 
-  public static String toUnified(PatchSet.Id diffBase,
+  public static String toUnified(DiffObject diffBase,
       PatchSet.Id revision, String fileName) {
     return toPatch("unified", diffBase, revision, fileName, null, 0);
   }
 
-  public static String toUnified(PatchSet.Id diffBase, Patch.Key id) {
+  public static String toUnified(DiffObject diffBase, Patch.Key id) {
     return toPatch("unified", diffBase, id);
   }
 
-  public static String toPatch(String type, PatchSet.Id diffBase, Patch.Key id) {
+  public static String toPatch(String type, DiffObject diffBase, Patch.Key id) {
     return toPatch(type, diffBase, id.getParentKey(), id.get(), null, 0);
   }
 
@@ -145,16 +145,16 @@
   }
 
   public static String toEditScreen(PatchSet.Id revision, String fileName, int line) {
-    return toPatch("edit", null, revision, fileName, null, line);
+    return toPatch("edit", DiffObject.base(), revision, fileName, null, line);
   }
 
-  private static String toPatch(String type, PatchSet.Id diffBase,
+  private static String toPatch(String type, DiffObject diffBase,
       PatchSet.Id revision, String fileName, DisplaySide side, int line) {
     Change.Id c = revision.getParentKey();
     StringBuilder p = new StringBuilder();
     p.append("/c/").append(c).append("/");
-    if (diffBase != null) {
-      p.append(diffBase.get()).append("..");
+    if (diffBase != null && diffBase.asString() != null) {
+      p.append(diffBase.asString()).append("..");
     }
     p.append(revision.getId()).append("/").append(KeyUtil.encode(fileName));
     if (type != null && !type.isEmpty()
@@ -395,7 +395,7 @@
         panel = null;
       }
       Gerrit.display(token, panel == null
-          ? new ChangeScreen(id, null, null, false, mode)
+          ? new ChangeScreen(id, DiffObject.base(), null, false, mode)
           : new NotFoundScreen());
       return;
     }
@@ -410,11 +410,14 @@
       rest = "";
     }
 
-    PatchSet.Id base = null;
+    DiffObject base = DiffObject.base();
     PatchSet.Id ps;
     int dotdot = psIdStr.indexOf("..");
     if (1 <= dotdot) {
-      base = new PatchSet.Id(id, Integer.parseInt(psIdStr.substring(0, dotdot)));
+      base = DiffObject.parse(id, psIdStr.substring(0, dotdot));
+      if (base == null) {
+        Gerrit.display(token, new NotFoundScreen());
+      }
       psIdStr = psIdStr.substring(dotdot + 2);
     }
     ps = toPsId(id, psIdStr);
@@ -438,9 +441,7 @@
       if (panel == null) {
         Gerrit.display(token,
             new ChangeScreen(id,
-                base != null
-                    ? String.valueOf(base.get())
-                    : null,
+                base,
                 String.valueOf(ps.get()), false, FileTable.Mode.REVIEW));
       } else {
         Gerrit.display(token, new NotFoundScreen());
@@ -464,7 +465,7 @@
   }
 
   private static void patch(String token,
-      PatchSet.Id baseId,
+      DiffObject base,
       Patch.Key id,
       DisplaySide side,
       int line,
@@ -477,14 +478,14 @@
 
     if ("".equals(panel) || /* DEPRECATED URL */"cm".equals(panel)) {
       if (preferUnified()) {
-        unified(token, baseId, id, side, line);
+        unified(token, base, id, side, line);
       } else {
-        codemirror(token, baseId, id, side, line);
+        codemirror(token, base, id, side, line);
       }
     } else if ("sidebyside".equals(panel)) {
-      codemirror(token, baseId, id, side, line);
+      codemirror(token, base, id, side, line);
     } else if ("unified".equals(panel)) {
-      unified(token, baseId, id, side, line);
+      unified(token, base, id, side, line);
     } else if ("edit".equals(panel)) {
       if (!Patch.isMagic(id.get()) || Patch.COMMIT_MSG.equals(id.get())) {
         codemirrorForEdit(token, id, line);
@@ -501,24 +502,24 @@
         || (UserAgent.isPortrait() && UserAgent.isMobile());
   }
 
-  private static void unified(final String token, final PatchSet.Id baseId,
+  private static void unified(final String token, final DiffObject base,
       final Patch.Key id, final DisplaySide side, final int line) {
     GWT.runAsync(new AsyncSplit(token) {
       @Override
       public void onSuccess() {
-        Gerrit.display(token,
-            new Unified(baseId, id.getParentKey(), id.get(), side, line));
+        Gerrit.display(token, new Unified(base,
+            DiffObject.patchSet(id.getParentKey()), id.get(), side, line));
       }
     });
   }
 
-  private static void codemirror(final String token, final PatchSet.Id baseId,
+  private static void codemirror(final String token, final DiffObject base,
       final Patch.Key id, final DisplaySide side, final int line) {
     GWT.runAsync(new AsyncSplit(token) {
       @Override
       public void onSuccess() {
-        Gerrit.display(token,
-            new SideBySide(baseId, id.getParentKey(), id.get(), side, line));
+        Gerrit.display(token, new SideBySide(base,
+            DiffObject.patchSet(id.getParentKey()), id.get(), side, line));
       }
     });
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
index 60911e1..436e0c3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
@@ -15,10 +15,12 @@
 package com.google.gerrit.client.change;
 
 import com.google.gerrit.client.AvatarImage;
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.ErrorDialog;
 import com.google.gerrit.client.FormatUtil;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.GerritUiExtensionPoint;
+import com.google.gerrit.client.NotFoundScreen;
 import com.google.gerrit.client.api.ChangeGlue;
 import com.google.gerrit.client.api.ExtensionPanel;
 import com.google.gerrit.client.changes.ChangeApi;
@@ -146,7 +148,7 @@
   }
 
   private final Change.Id changeId;
-  private String base;
+  private DiffObject base;
   private String revision;
   private ChangeInfo changeInfo;
   private boolean hasDraftComments;
@@ -239,10 +241,10 @@
   private DeleteFileAction deleteFileAction;
   private RenameFileAction renameFileAction;
 
-  public ChangeScreen(Change.Id changeId, String base, String revision,
+  public ChangeScreen(Change.Id changeId, DiffObject base, String revision,
       boolean openReplyBox, FileTable.Mode mode) {
     this.changeId = changeId;
-    this.base = normalize(base);
+    this.base = base;
     this.revision = normalize(revision);
     this.openReplyBox = openReplyBox;
     this.fileTableMode = mode;
@@ -299,9 +301,10 @@
             group.addListener(new GerritCallback<Void>() {
               @Override
               public void onSuccess(Void result) {
-                if (base == null && rev.commit().parents().length() > 1) {
-                  base = Gerrit.getUserPreferences()
-                      .defaultBaseForMerges().getBase();
+                if (base.isBase() && rev.isMerge()) {
+                  base = DiffObject.parse(info.legacyId(),
+                      Gerrit.getUserPreferences()
+                          .defaultBaseForMerges().getBase());
                 }
                 loadConfigInfo(info, base);
                 JsArray<MessageInfo> mAr = info.messages();
@@ -915,7 +918,7 @@
     int idx = diffBase.getSelectedIndex();
     if (0 <= idx) {
       String n = diffBase.getValue(idx);
-      loadConfigInfo(changeInfo, !n.isEmpty() ? n : null);
+      loadConfigInfo(changeInfo, DiffObject.parse(changeInfo.legacyId(), n));
     }
   }
 
@@ -968,13 +971,20 @@
     int idx = diffBase.getSelectedIndex();
     if (0 <= idx) {
       String n = diffBase.getValue(idx);
-      loadConfigInfo(changeInfo, !n.isEmpty() ? n : null);
+      loadConfigInfo(changeInfo, DiffObject.parse(changeInfo.legacyId(), n));
     }
   }
 
-  private void loadConfigInfo(final ChangeInfo info, String base) {
+  private void loadConfigInfo(final ChangeInfo info, DiffObject base) {
     final RevisionInfo rev = info.revision(revision);
-    RevisionInfo b = resolveRevisionOrPatchSetId(info, base, null);
+    if (base.isAutoMerge() && !initCurrentRevision(info).isMerge()) {
+      Gerrit.display(getToken(), new NotFoundScreen());
+    }
+
+    updateToken(info, base, rev);
+
+    RevisionInfo baseRev =
+        resolveRevisionOrPatchSetId(info, base.asString(), null);
 
     CallbackGroup group = new CallbackGroup();
     Timestamp lastReply = myLastReply(info);
@@ -984,9 +994,9 @@
       RevisionInfo p = RevisionInfo.findEditParentRevision(
           info.revisions().values());
       List<NativeMap<JsArray<CommentInfo>>> comments = loadComments(p, group);
-      loadFileList(b, rev, lastReply, group, comments, null);
+      loadFileList(base, baseRev, rev, lastReply, group, comments, null);
     } else {
-      loadDiff(b, rev, lastReply, group);
+      loadDiff(base, baseRev, rev, lastReply, group);
     }
     group.addListener(new AsyncCallback<Void>() {
       @Override
@@ -1025,6 +1035,21 @@
       });
   }
 
+  private void updateToken(ChangeInfo info, DiffObject base, RevisionInfo rev) {
+    StringBuilder token = new StringBuilder("/c/")
+        .append(info._number())
+        .append("/");
+    if (base.asString() != null) {
+      token.append(base.asString())
+          .append("..");
+    }
+    if (base.asString() != null
+        || !rev.name().equals(info.currentRevision())) {
+      token.append(rev._number());
+    }
+    setToken(token.toString());
+  }
+
   static Timestamp myLastReply(ChangeInfo info) {
     if (Gerrit.isSignedIn() && info.messages() != null) {
       int self = Gerrit.getUserAccount()._accountId();
@@ -1038,11 +1063,11 @@
     return null;
   }
 
-  private void loadDiff(RevisionInfo base, RevisionInfo rev,
+  private void loadDiff(DiffObject base, RevisionInfo baseRev, RevisionInfo rev,
       Timestamp myLastReply, CallbackGroup group) {
     List<NativeMap<JsArray<CommentInfo>>> comments = loadComments(rev, group);
     List<NativeMap<JsArray<CommentInfo>>> drafts = loadDrafts(rev, group);
-    loadFileList(base, rev, myLastReply, group, comments, drafts);
+    loadFileList(base, baseRev, rev, myLastReply, group, comments, drafts);
 
     if (Gerrit.isSignedIn() && fileTableMode == FileTable.Mode.REVIEW) {
       ChangeApi.revision(changeId.get(), rev.name())
@@ -1061,19 +1086,19 @@
     }
   }
 
-  private void loadFileList(final RevisionInfo base, final RevisionInfo rev,
-      final Timestamp myLastReply, CallbackGroup group,
+  private void loadFileList(final DiffObject base, final RevisionInfo baseRev,
+      final RevisionInfo rev, final Timestamp myLastReply, CallbackGroup group,
       final List<NativeMap<JsArray<CommentInfo>>> comments,
       final List<NativeMap<JsArray<CommentInfo>>> drafts) {
     DiffApi.list(changeId.get(),
         rev.name(),
-        base,
+        baseRev,
         group.add(
             new AsyncCallback<NativeMap<FileInfo>>() {
               @Override
               public void onSuccess(NativeMap<FileInfo> m) {
                 files.set(
-                    base != null ? new PatchSet.Id(changeId, base._number()) : null,
+                    base,
                     new PatchSet.Id(changeId, rev._number()),
                     style, reply, fileTableMode, edit != null);
                 files.setValue(m, myLastReply,
@@ -1475,12 +1500,12 @@
       RevisionInfo r = list.get(i);
       diffBase.addItem(
         r.id() + ": " + r.name().substring(0, 6),
-        r.name());
+        r.id());
       if (r.name().equals(revision)) {
         SelectElement.as(diffBase.getElement()).getOptions()
             .getItem(diffBase.getItemCount() - 1).setDisabled(true);
       }
-      if (base != null && base.equals(String.valueOf(r._number()))) {
+      if (base.isPatchSet() && base.asPatchSetId().get() == r._number()) {
         selectedIdx = diffBase.getItemCount() - 1;
       }
     }
@@ -1488,15 +1513,15 @@
     RevisionInfo rev = info.revisions().get(revision);
     JsArray<CommitInfo> parents = rev.commit().parents();
     if (parents.length() > 1) {
-      diffBase.addItem(Util.C.autoMerge(), "");
+      diffBase.addItem(Util.C.autoMerge(), DiffObject.AUTO_MERGE);
       for (int i = 0; i < parents.length(); i++) {
         int parentNum = i + 1;
         diffBase.addItem(Util.M.diffBaseParent(parentNum),
             String.valueOf(-parentNum));
       }
-      int parentNum = toParentNum(base);
-      if (parentNum > 0) {
-        selectedIdx = list.length() + parentNum;
+
+      if (base.isParent()) {
+        selectedIdx = list.length() + base.getParentNum();
       }
     } else {
       diffBase.addItem(Util.C.baseDiffItem(), "");
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
index 3a85b26..a95270b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
@@ -19,6 +19,7 @@
 import static com.google.gerrit.client.FormatUtil.formatBytes;
 import static com.google.gerrit.client.FormatUtil.formatPercentage;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.VoidResult;
@@ -182,7 +183,7 @@
     return null;
   }
 
-  private PatchSet.Id base;
+  private DiffObject base;
   private PatchSet.Id curr;
   private MyTable table;
   private boolean register;
@@ -199,7 +200,7 @@
     R.css().ensureInjected();
   }
 
-  public void set(PatchSet.Id base, PatchSet.Id curr, ChangeScreen.Style style,
+  public void set(DiffObject base, PatchSet.Id curr, ChangeScreen.Style style,
       Widget replyButton, Mode mode, boolean editExists) {
     this.base = base;
     this.curr = curr;
@@ -340,7 +341,7 @@
       });
 
       setSavePointerId(
-          (base != null ? base.toString() + ".." : "")
+          (!base.isBase() ? base.asString() + ".." : "")
           + curr.toString());
     }
 
@@ -789,9 +790,9 @@
       for (CommentInfo c : Natives.asList(list)) {
         if (c.side() == Side.REVISION) {
           result.push(c);
-        } else if (base == null && !c.hasParent()) {
+        } else if (base.isBaseOrAutoMerge() && !c.hasParent()) {
           result.push(c);
-        } else if (base != null && c.parent() == -base.get()) {
+        } else if (base.isParent() && c.parent() == base.getParentNum()) {
           result.push(c);
         }
       }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
index 2f3ead3..4c01941 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.client.diff;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.changes.CommentInfo;
 import com.google.gerrit.client.patches.SkippedLine;
@@ -40,7 +41,7 @@
 
 /** Tracks comment widgets for {@link DiffScreen}. */
 abstract class CommentManager {
-  private final PatchSet.Id base;
+  private final DiffObject base;
   private final PatchSet.Id revision;
   private final String path;
   private final CommentLinkProcessor commentLinkProcessor;
@@ -55,7 +56,7 @@
 
   CommentManager(
       DiffScreen host,
-      PatchSet.Id base,
+      DiffObject base,
       PatchSet.Id revision,
       String path,
       CommentLinkProcessor clp,
@@ -129,29 +130,30 @@
   }
 
   Side getStoredSideFromDisplaySide(DisplaySide side) {
-    if (side == DisplaySide.A && (base == null || base.get() < 0)) {
+    if (side == DisplaySide.A && base.isBaseOrAutoMerge() || base.isParent()) {
       return Side.PARENT;
     }
     return Side.REVISION;
   }
 
   int getParentNumFromDisplaySide(DisplaySide side) {
-    if (side == DisplaySide.A && base != null && base.get() < 0) {
-      return -base.get();
+    if (side == DisplaySide.A) {
+      return base.getParentNum();
     }
     return 0;
   }
 
   PatchSet.Id getPatchSetIdFromSide(DisplaySide side) {
-    if (side == DisplaySide.A && base != null && base.get() >= 0) {
-      return base;
+    if (side == DisplaySide.A && (base.isPatchSet() || base.isEdit())) {
+      return base.asPatchSetId();
     }
     return revision;
   }
 
   DisplaySide displaySide(CommentInfo info, DisplaySide forSide) {
     if (info.side() == Side.PARENT) {
-      return (base == null || base.get() < 0) ? DisplaySide.A : null;
+      return (base.isBaseOrAutoMerge() || base.isParent())
+          ? DisplaySide.A : null;
     }
     return forSide;
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java
index ce1d294..0b8e141 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.client.diff;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.changes.CommentApi;
 import com.google.gerrit.client.changes.CommentInfo;
@@ -31,7 +32,7 @@
 /** Collection of published and draft comments loaded from the server. */
 class CommentsCollections {
   private final String path;
-  private final PatchSet.Id base;
+  private final DiffObject base;
   private final PatchSet.Id revision;
   private NativeMap<JsArray<CommentInfo>> publishedBaseAll;
   private NativeMap<JsArray<CommentInfo>> publishedRevisionAll;
@@ -40,28 +41,28 @@
   JsArray<CommentInfo> draftsBase;
   JsArray<CommentInfo> draftsRevision;
 
-  CommentsCollections(PatchSet.Id base, PatchSet.Id revision, String path) {
+  CommentsCollections(DiffObject base, PatchSet.Id revision, String path) {
     this.path = path;
     this.base = base;
     this.revision = revision;
   }
 
   void load(CallbackGroup group) {
-    if (base != null && base.get() > 0) {
-      CommentApi.comments(base, group.add(publishedBase()));
+    if (base.isPatchSet()) {
+      CommentApi.comments(base.asPatchSetId(), group.add(publishedBase()));
     }
     CommentApi.comments(revision, group.add(publishedRevision()));
 
     if (Gerrit.isSignedIn()) {
-      if (base != null && base.get() > 0) {
-        CommentApi.drafts(base, group.add(draftsBase()));
+      if (base.isPatchSet()) {
+        CommentApi.drafts(base.asPatchSetId(), group.add(draftsBase()));
       }
       CommentApi.drafts(revision, group.add(draftsRevision()));
     }
   }
 
   boolean hasCommentForPath(String filePath) {
-    if (base != null && base.get() > 0) {
+    if (base.isPatchSet()) {
       JsArray<CommentInfo> forBase = publishedBaseAll.get(filePath);
       if (forBase != null && forBase.length() > 0) {
         return true;
@@ -110,9 +111,9 @@
       for (CommentInfo c : Natives.asList(list)) {
         if (c.side() == Side.REVISION) {
           result.push(c);
-        } else if (base == null && !c.hasParent()) {
+        } else if (base.isBaseOrAutoMerge() && !c.hasParent()) {
           result.push(c);
-        } else if (base != null && c.parent() == -base.get()) {
+        } else if (base.isParent() && c.parent() == base.getParentNum()) {
           result.push(c);
         }
       }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffScreen.java
index de19b35..a22d4bd 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffScreen.java
@@ -17,6 +17,7 @@
 import static com.google.gerrit.extensions.client.DiffPreferencesInfo.WHOLE_FILE_CONTEXT;
 import static java.lang.Double.POSITIVE_INFINITY;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.account.DiffPreferences;
@@ -96,7 +97,7 @@
   }
 
   private final Change.Id changeId;
-  final PatchSet.Id base;
+  final DiffObject base;
   final PatchSet.Id revision;
   final String path;
   final DiffPreferences prefs;
@@ -123,15 +124,15 @@
   Header header;
 
   DiffScreen(
-      PatchSet.Id base,
-      PatchSet.Id revision,
+      DiffObject base,
+      DiffObject revision,
       String path,
       DisplaySide startSide,
       int startLine,
       DiffView diffScreenType) {
     this.base = base;
-    this.revision = revision;
-    this.changeId = revision.getParentKey();
+    this.revision = revision.asPatchSetId();
+    this.changeId = revision.asPatchSetId().getParentKey();
     this.path = path;
     this.startSide = startSide;
     this.startLine = startLine;
@@ -173,7 +174,7 @@
     }));
 
     DiffApi.diff(revision, path)
-      .base(base)
+      .base(base.asPatchSetId())
       .wholeFile()
       .intraline(prefs.intralineDifference())
       .ignoreWhitespace(prefs.ignoreWhitespace())
@@ -789,11 +790,10 @@
         group.addListener(new GerritCallback<Void>() {
           @Override
           public void onSuccess(Void result) {
-            String b = base != null ? String.valueOf(base.get()) : null;
             String rev = String.valueOf(revision.get());
             Gerrit.display(
-              PageLinks.toChange(changeId, b, rev),
-              new ChangeScreen(changeId, b, rev, openReplyBox,
+              PageLinks.toChange(changeId, base.asString(), rev),
+              new ChangeScreen(changeId, base, rev, openReplyBox,
                   FileTable.Mode.REVIEW));
           }
         });
@@ -901,7 +901,7 @@
     String nextPath = header.getNextPath();
     if (nextPath != null) {
       DiffApi.diff(revision, nextPath)
-        .base(base)
+        .base(base.asPatchSetId())
         .wholeFile()
         .intraline(prefs.intralineDifference())
         .ignoreWhitespace(prefs.ignoreWhitespace())
@@ -924,7 +924,7 @@
   void reloadDiffInfo() {
     final int id = ++reloadVersionId;
     DiffApi.diff(revision, path)
-      .base(base)
+      .base(base.asPatchSetId())
       .wholeFile()
       .intraline(prefs.intralineDifference())
       .ignoreWhitespace(prefs.ignoreWhitespace())
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java
index 392ad2f..54b55f04 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.client.diff;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.account.DiffPreferences;
 import com.google.gerrit.client.info.ChangeInfo.RevisionInfo;
 import com.google.gerrit.reviewdb.client.Patch.ChangeType;
@@ -66,11 +67,12 @@
   private ChangeType changeType;
   Scrollbar scrollbar;
 
-  DiffTable(DiffScreen parent, PatchSet.Id base, PatchSet.Id revision, String path) {
-    patchSetSelectBoxA = new PatchSetSelectBox(
-        parent, DisplaySide.A, revision.getParentKey(), base, path);
-    patchSetSelectBoxB = new PatchSetSelectBox(
-        parent, DisplaySide.B, revision.getParentKey(), revision, path);
+  DiffTable(DiffScreen parent, DiffObject base, DiffObject revision,
+      String path) {
+    patchSetSelectBoxA = new PatchSetSelectBox(parent, DisplaySide.A,
+        revision.asPatchSetId().getParentKey(), base, path);
+    patchSetSelectBoxB = new PatchSetSelectBox(parent, DisplaySide.B,
+        revision.asPatchSetId().getParentKey(), revision, path);
     PatchSetSelectBox.link(patchSetSelectBoxA, patchSetSelectBoxB);
 
     this.scrollbar = new Scrollbar(this);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
index 3033cbb1..f3b9886 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.client.diff;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.account.DiffPreferences;
@@ -87,7 +88,7 @@
   @UiField Image preferences;
 
   private final KeyCommandSet keys;
-  private final PatchSet.Id base;
+  private final DiffObject base;
   private final PatchSet.Id patchSetId;
   private final String path;
   private final DiffView diffScreenType;
@@ -99,12 +100,12 @@
   private PreferencesAction prefsAction;
   private ReviewedState reviewedState;
 
-  Header(KeyCommandSet keys, PatchSet.Id base, PatchSet.Id patchSetId,
+  Header(KeyCommandSet keys, DiffObject base, DiffObject patchSetId,
       String path, DiffView diffSreenType, DiffPreferences prefs) {
     initWidget(uiBinder.createAndBindUi(this));
     this.keys = keys;
     this.base = base;
-    this.patchSetId = patchSetId;
+    this.patchSetId = patchSetId.asPatchSetId();
     this.path = path;
     this.diffScreenType = diffSreenType;
     this.prefs = prefs;
@@ -113,9 +114,9 @@
       reviewed.getElement().getStyle().setVisibility(Visibility.HIDDEN);
     }
     SafeHtml.setInnerHTML(filePath, formatPath(path));
-    up.setTargetHistoryToken(PageLinks.toChange(
-        patchSetId.getParentKey(),
-        base != null ? base.getId() : null, patchSetId.getId()));
+    up.setTargetHistoryToken(
+        PageLinks.toChange(patchSetId.asPatchSetId().getParentKey(),
+            base.asString(), patchSetId.asPatchSetId().getId()));
   }
 
   public static SafeHtml formatPath(String path) {
@@ -147,16 +148,17 @@
 
   @Override
   protected void onLoad() {
-    DiffApi.list(patchSetId, base, new GerritCallback<NativeMap<FileInfo>>() {
-      @Override
-      public void onSuccess(NativeMap<FileInfo> result) {
-        files = result.values();
-        FileInfo.sortFileInfoByPath(files);
-        fileNumber.setInnerText(
-            Integer.toString(Natives.asList(files).indexOf(result.get(path)) + 1));
-        fileCount.setInnerText(Integer.toString(files.length()));
-      }
-    });
+    DiffApi.list(patchSetId, base.asPatchSetId(),
+        new GerritCallback<NativeMap<FileInfo>>() {
+          @Override
+          public void onSuccess(NativeMap<FileInfo> result) {
+            files = result.values();
+            FileInfo.sortFileInfoByPath(files);
+            fileNumber.setInnerText(Integer
+                .toString(Natives.asList(files).indexOf(result.get(path)) + 1));
+            fileCount.setInnerText(Integer.toString(files.length()));
+          }
+        });
 
     if (Gerrit.isSignedIn()) {
       ChangeApi.revision(patchSetId).view("files")
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java
index d45b8d8..b07a199 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.client.diff;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.blame.BlameInfo;
@@ -67,13 +68,13 @@
   private String path;
   private Change.Id changeId;
   private PatchSet.Id revision;
-  private PatchSet.Id idActive;
+  private DiffObject idActive;
   private PatchSetSelectBox other;
 
   PatchSetSelectBox(DiffScreen parent,
       DisplaySide side,
       Change.Id changeId,
-      PatchSet.Id revision,
+      DiffObject diffObject,
       String path) {
     initWidget(uiBinder.createAndBindUi(this));
     icon.setTitle(PatchUtil.C.addFileCommentToolTip());
@@ -83,8 +84,8 @@
     this.side = side;
     this.sideA = side == DisplaySide.A;
     this.changeId = changeId;
-    this.revision = revision;
-    this.idActive = (sideA && revision == null) ? null : revision;
+    this.revision = diffObject.asPatchSetId();
+    this.idActive = diffObject;
     this.path = path;
   }
 
@@ -93,19 +94,22 @@
     InlineHyperlink selectedLink = null;
     if (sideA) {
       if (parents <= 1) {
-        InlineHyperlink link = createLink(PatchUtil.C.patchBase(), null);
+        InlineHyperlink link =
+            createLink(PatchUtil.C.patchBase(), DiffObject.base());
         linkPanel.add(link);
         selectedLink = link;
       } else {
         for (int i = parents; i > 0; i--) {
           PatchSet.Id id = new PatchSet.Id(changeId, -i);
-          InlineHyperlink link = createLink(Util.M.diffBaseParent(i), id);
+          InlineHyperlink link =
+              createLink(Util.M.diffBaseParent(i), DiffObject.patchSet(id));
           linkPanel.add(link);
           if (revision != null && id.equals(revision)) {
             selectedLink = link;
           }
         }
-        InlineHyperlink link = createLink(Util.C.autoMerge(), null);
+        InlineHyperlink link =
+            createLink(Util.C.autoMerge(), DiffObject.autoMerge());
         linkPanel.add(link);
         if (selectedLink == null) {
           selectedLink = link;
@@ -115,7 +119,7 @@
     for (int i = 0; i < list.length(); i++) {
       RevisionInfo r = list.get(i);
       InlineHyperlink link = createLink(r.id(),
-          new PatchSet.Id(changeId, r._number()));
+          DiffObject.patchSet(new PatchSet.Id(changeId, r._number())));
       linkPanel.add(link);
       if (revision != null && r.id().equals(revision.getId())) {
         selectedLink = link;
@@ -131,8 +135,8 @@
     if (!Patch.isMagic(path)) {
       linkPanel.add(createDownloadLink());
     }
-    if (!binary && open && idActive != null && Gerrit.isSignedIn()) {
-      if ((editExists && idActive.get() == 0)
+    if (!binary && open && !idActive.isBaseOrAutoMerge() && Gerrit.isSignedIn()) {
+      if ((editExists && idActive.isEdit())
           || (!editExists && current)) {
         linkPanel.add(createEditIcon());
       }
@@ -172,7 +176,9 @@
   }
 
   private Widget createEditIcon() {
-    PatchSet.Id id = (idActive == null) ? other.idActive : idActive;
+    PatchSet.Id id = idActive.isBaseOrAutoMerge()
+        ? other.idActive.asPatchSetId()
+        : idActive.asPatchSetId();
     Anchor anchor = new Anchor(
         new ImageResourceRenderer().render(Gerrit.RESOURCES.edit()),
         "#" + Dispatcher.toEditScreen(id, path));
@@ -192,27 +198,29 @@
     b.other = a;
   }
 
-  private InlineHyperlink createLink(String label, PatchSet.Id id) {
+  private InlineHyperlink createLink(String label, DiffObject id) {
     assert other != null;
     if (sideA) {
-      assert other.idActive != null;
+      assert !other.idActive.isBaseOrAutoMerge();
     }
-    PatchSet.Id diffBase = sideA ? id : other.idActive;
-    PatchSet.Id revision = sideA ? other.idActive : id;
+    DiffObject diffBase = sideA ? id : other.idActive;
+    DiffObject revision = sideA ? other.idActive : id;
 
     return new InlineHyperlink(label,
         parent.isSideBySide()
-            ? Dispatcher.toSideBySide(diffBase, revision, path)
-            : Dispatcher.toUnified(diffBase, revision, path));
+            ? Dispatcher.toSideBySide(diffBase, revision.asPatchSetId(), path)
+            : Dispatcher.toUnified(diffBase, revision.asPatchSetId(), path));
   }
 
   private Anchor createDownloadLink() {
-    PatchSet.Id id = (idActive == null) ? other.idActive : idActive;
-    String sideURL = (idActive == null) ? "1" : "0";
+    DiffObject diffObject = idActive.isBaseOrAutoMerge()
+        ? other.idActive : idActive;
+    String sideURL = idActive.isBaseOrAutoMerge() ? "1" : "0";
     String base = GWT.getHostPageBaseURL() + "cat/";
     Anchor anchor = new Anchor(
         new ImageResourceRenderer().render(Gerrit.RESOURCES.downloadIcon()),
-        base + KeyUtil.encode(id + "," + path) + "^" + sideURL);
+        base + KeyUtil.encode(diffObject.asPatchSetId() + "," + path) + "^"
+            + sideURL);
     anchor.setTitle(PatchUtil.C.download());
     return anchor;
   }
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 dbe7e5d..6e2120a 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
@@ -16,6 +16,7 @@
 
 import static java.lang.Double.POSITIVE_INFINITY;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.diff.LineMapper.LineOnOtherInfo;
@@ -25,7 +26,6 @@
 import com.google.gerrit.client.ui.InlineHyperlink;
 import com.google.gerrit.extensions.client.GeneralPreferencesInfo.DiffView;
 import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
@@ -69,8 +69,8 @@
   private SideBySideCommentManager commentManager;
 
   public SideBySide(
-      PatchSet.Id base,
-      PatchSet.Id revision,
+      DiffObject base,
+      DiffObject revision,
       String path,
       DisplaySide startSide,
       int startLine) {
@@ -192,9 +192,8 @@
     cmA = newCm(diff.metaA(), diff.textA(), diffTable.cmA);
     cmB = newCm(diff.metaB(), diff.textB(), diffTable.cmB);
 
-    boolean reviewingBase = base == null;
-    getDiffTable().setUpBlameIconA(cmA, reviewingBase,
-        reviewingBase ? revision : base, path);
+    getDiffTable().setUpBlameIconA(cmA, base.isBaseOrAutoMerge(),
+        base.isBaseOrAutoMerge() ? revision : base.asPatchSetId(), path);
     getDiffTable().setUpBlameIconB(cmB, revision, path);
 
     cmA.extras().side(DisplaySide.A);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java
index bcb7dac..fab6e6b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.client.diff;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.changes.CommentInfo;
 import com.google.gerrit.client.ui.CommentLinkProcessor;
@@ -29,7 +30,7 @@
 /** Tracks comment widgets for {@link SideBySide}. */
 class SideBySideCommentManager extends CommentManager {
   SideBySideCommentManager(SideBySide host,
-      PatchSet.Id base, PatchSet.Id revision,
+      DiffObject base, PatchSet.Id revision,
       String path,
       CommentLinkProcessor clp,
       boolean open) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideTable.java
index 2296796..5e8d7cc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideTable.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.client.diff;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.reviewdb.client.Patch.ChangeType;
-import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.resources.client.CssResource;
@@ -46,7 +46,7 @@
 
   private boolean visibleA;
 
-  SideBySideTable(SideBySide parent, PatchSet.Id base, PatchSet.Id revision,
+  SideBySideTable(SideBySide parent, DiffObject base, DiffObject revision,
       String path) {
     super(parent, base, revision, path);
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Unified.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Unified.java
index a231580..566d87c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Unified.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Unified.java
@@ -16,6 +16,7 @@
 
 import static java.lang.Double.POSITIVE_INFINITY;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.diff.UnifiedChunkManager.LineRegionInfo;
@@ -25,7 +26,6 @@
 import com.google.gerrit.client.ui.InlineHyperlink;
 import com.google.gerrit.extensions.client.GeneralPreferencesInfo.DiffView;
 import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.core.client.JsArrayString;
@@ -69,8 +69,8 @@
   private boolean autoHideDiffTableHeader;
 
   public Unified(
-      PatchSet.Id base,
-      PatchSet.Id revision,
+      DiffObject base,
+      DiffObject revision,
       String path,
       DisplaySide startSide,
       int startLine) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java
index 8968bc7..21356fc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.client.diff;
 
+import com.google.gerrit.client.DiffObject;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.changes.CommentInfo;
 import com.google.gerrit.client.diff.LineMapper.LineOnOtherInfo;
@@ -43,7 +44,7 @@
   private final Map<Integer, CommentGroup> duplicates;
 
   UnifiedCommentManager(Unified host,
-      PatchSet.Id base, PatchSet.Id revision,
+      DiffObject base, PatchSet.Id revision,
       String path,
       CommentLinkProcessor clp,
       boolean open) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedTable.java
index 72b3e49..e3317c4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedTable.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.client.diff;
 
-import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.client.DiffObject;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.resources.client.CssResource;
@@ -45,7 +45,7 @@
   @UiField Element cm;
   @UiField static DiffTableStyle style;
 
-  UnifiedTable(Unified parent, PatchSet.Id base, PatchSet.Id revision,
+  UnifiedTable(Unified parent, DiffObject base, DiffObject revision,
       String path) {
     super(parent, base, revision, path);