Merge "Tokenized REST API POST handler"
diff --git a/Documentation/licenses.txt b/Documentation/licenses.txt
index 4186026..7787fe8 100644
--- a/Documentation/licenses.txt
+++ b/Documentation/licenses.txt
@@ -28,7 +28,7 @@
 |Apache Commons Pool        | <<apache2,Apache License 2.0>>
 |Apache Log4J               | <<apache2,Apache License 2.0>>
 |Apache MINA                | <<apache2,Apache License 2.0>>
-|Apache Tomact Servlet API  | <<apache2,Apache License 2.0>>
+|Apache Tomcat Servlet API  | <<apache2,Apache License 2.0>>
 |Apache SSHD                | <<apache2,Apache License 2.0>>, see also <<sshd,NOTICE>>
 |Apache Velocity            | <<apache2,Apache License 2.0>>
 |Apache Xerces              | <<apache2,Apache License 2.0>>
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 1b23804..be74428 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
@@ -15,6 +15,7 @@
 package com.google.gerrit.client;
 
 import static com.google.gerrit.common.data.GlobalCapability.ADMINISTRATE_SERVER;
+import static com.google.gerrit.common.data.GlobalCapability.CREATE_PROJECT;
 
 import com.google.gerrit.client.account.AccountCapabilities;
 import com.google.gerrit.client.auth.openid.OpenIdSignInDialog;
@@ -584,10 +585,23 @@
     addDiffLink(diffBar, C.menuDiffPatchSets(), PatchScreen.TopView.PATCH_SETS);
     addDiffLink(diffBar, C.menuDiffFiles(), PatchScreen.TopView.FILES);
 
+    final LinkMenuBar projectsBar = new LinkMenuBar();
+    addLink(projectsBar, C.menuProjectsList(), PageLinks.ADMIN_PROJECTS);
+    if(signedIn) {
+      AccountCapabilities.all(new GerritCallback<AccountCapabilities>() {
+        @Override
+        public void onSuccess(AccountCapabilities result) {
+          if (result.canPerform(CREATE_PROJECT)) {
+            addLink(projectsBar, C.menuProjectsCreate(), PageLinks.ADMIN_CREATE_PROJECT);
+          }
+        }
+      }, CREATE_PROJECT);
+    }
+    menuLeft.add(projectsBar, C.menuProjects());
+
     if (signedIn) {
       final LinkMenuBar menuBar = new LinkMenuBar();
       addLink(menuBar, C.menuGroups(), PageLinks.ADMIN_GROUPS);
-      addLink(menuBar, C.menuProjects(), PageLinks.ADMIN_PROJECTS);
       AccountCapabilities.all(new GerritCallback<AccountCapabilities>() {
         @Override
         public void onSuccess(AccountCapabilities result) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
index 09e6b84..c47c789 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
@@ -68,10 +68,13 @@
   String menuDiffPatchSets();
   String menuDiffFiles();
 
+  String menuProjects();
+  String menuProjectsList();
+  String menuProjectsCreate();
+
   String menuAdmin();
   String menuPeople();
   String menuGroups();
-  String menuProjects();
   String menuPlugins();
 
   String menuDocumentation();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
index 294ba49..67ebe2a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
@@ -51,10 +51,13 @@
 menuDiffPatchSets = Patch Sets
 menuDiffFiles = Files
 
+menuProjects = Projects
+menuProjectsList = List
+menuProjectsCreate = Create New Project
+
 menuAdmin = Admin
 menuPeople = People
 menuGroups = Groups
-menuProjects = Projects
 menuPlugins = Plugins
 
 menuDocumentation = Documentation
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
index cb40d69..9cbf5cd 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
@@ -79,7 +79,6 @@
   String contributorAgreementShortDescription();
   String coverMessage();
   String createGroupLink();
-  String createProjectLink();
   String createProjectPanel();
   String dataCell();
   String dataHeader();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java
index b5c0900..d763ff1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java
@@ -39,4 +39,7 @@
 
   @Source("redNot.png")
   public ImageResource redNot();
+
+  @Source("downloadIcon.png")
+  public ImageResource downloadIcon();
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
index 2d49f5d..a085ce5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
@@ -60,7 +60,6 @@
   String noMembersInfo();
   String headingExternalGroup();
   String headingCreateGroup();
-  String headingCreateProject();
   String headingParentProjectName();
   String columnProjectName();
   String headingAgreements();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
index 17fba14..406f3d3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
@@ -41,7 +41,6 @@
 noMembersInfo = Group Members can only be viewed for Gerrit internal groups. For external groups and Gerrit system groups the members cannot be displayed.
 headingExternalGroup = Selected External Group
 headingCreateGroup = Create New Group
-headingCreateProject = Create New Project
 headingAgreements = Contributor Agreements
 
 projectSubmitType_FAST_FORWARD_ONLY = Fast Forward Only
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
index 5cb178c..d911c93 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
@@ -14,12 +14,7 @@
 
 package com.google.gerrit.client.admin;
 
-import static com.google.gerrit.common.data.GlobalCapability.CREATE_PROJECT;
-
 import com.google.gerrit.client.Dispatcher;
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.account.AccountCapabilities;
-import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.projects.ProjectInfo;
 import com.google.gerrit.client.projects.ProjectMap;
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
@@ -28,22 +23,13 @@
 import com.google.gerrit.client.ui.Screen;
 import com.google.gerrit.common.PageLinks;
 import com.google.gwt.user.client.History;
-import com.google.gwt.user.client.ui.VerticalPanel;
 
 public class ProjectListScreen extends Screen {
-  private VerticalPanel createProjectLinkPanel;
   private ProjectsTable projects;
 
   @Override
   protected void onLoad() {
     super.onLoad();
-    createProjectLinkPanel.setVisible(false);
-    AccountCapabilities.all(new GerritCallback<AccountCapabilities>() {
-      @Override
-      public void onSuccess(AccountCapabilities ac) {
-        createProjectLinkPanel.setVisible(ac.canPerform(CREATE_PROJECT));
-      }
-    }, CREATE_PROJECT);
     ProjectMap.all(new ScreenLoadCallback<ProjectMap>(this) {
       @Override
       protected void preDisplay(final ProjectMap result) {
@@ -58,13 +44,6 @@
     super.onInitUI();
     setPageTitle(Util.C.projectListTitle());
 
-    createProjectLinkPanel = new VerticalPanel();
-    createProjectLinkPanel.setStyleName(Gerrit.RESOURCES.css()
-        .createProjectLink());
-    createProjectLinkPanel.add(new Hyperlink(Util.C.headingCreateProject(),
-        PageLinks.ADMIN_CREATE_PROJECT));
-    add(createProjectLinkPanel);
-
     projects = new ProjectsTable() {
       @Override
       protected void onOpenRow(final int row) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
index 97bb4ca..3a13297 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
@@ -209,6 +209,8 @@
     if (! c.isLatest()) {
       s += " [OUTDATED]";
       table.getRowFormatter().addStyleName(row, Gerrit.RESOURCES.css().outdated());
+    } else if (Change.Status.ABANDONED.equals(c.getStatus())) {
+      table.getRowFormatter().addStyleName(row, Gerrit.RESOURCES.css().outdated());
     } else {
       table.getRowFormatter().removeStyleName(row, Gerrit.RESOURCES.css().outdated());
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java
index 005423f..b9ed4e7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java
@@ -89,6 +89,12 @@
     for (final PatchSet ps : patchSets) {
       final PatchSetComplexDisclosurePanel p =
           new PatchSetComplexDisclosurePanel(ps, ps == currps);
+      if (diffBaseId != null) {
+        p.setDiffBaseId(diffBaseId);
+        if (ps == currps) {
+          p.refresh();
+        }
+      }
       add(p);
       patchSetPanelsList.add(p);
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/downloadIcon.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/downloadIcon.png
new file mode 100644
index 0000000..22ff495
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/downloadIcon.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
index 533672e..7512d8c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
@@ -1153,10 +1153,6 @@
   margin-bottom: 10px;
 }
 
-.createProjectLink {
-  margin-bottom: 10px;
-}
-
 .createProjectPanel {
   margin-bottom: 10px;
   background-color: trimColor;
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 70dcf75..4801e65 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
@@ -48,6 +48,9 @@
   String fileList();
   String expandComment();
 
+  String toggleReviewed();
+  String markAsReviewedAndGoToNext();
+
   String commentEditorSet();
   String commentInsert();
   String commentSaveDraft();
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 694ccb4..11823ac 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
@@ -30,6 +30,9 @@
 fileList = Browse files in patch set
 expandComment = Expand or collapse comment
 
+toggleReviewed = Toggle the reviewed flag
+markAsReviewedAndGoToNext = Mark patch as reviewed and go to next unreviewed patch
+
 commentEditorSet = Comment Editing
 commentInsert = Create a new inline comment
 commentSaveDraft = Save draft comment
@@ -45,7 +48,7 @@
 
 reviewedAnd = Reviewed &
 next = next
-download = (Download)
+download = Download
 
 fileTypeSymlink = Type: Symbolic Link
 fileTypeGitlink = Type: Git Commit in Subproject
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
index 0976a9d..4f8731c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
@@ -25,8 +25,8 @@
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
 import com.google.gerrit.client.ui.ChangeLink;
+import com.google.gerrit.client.ui.InlineHyperlink;
 import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
-import com.google.gerrit.client.ui.PatchLink;
 import com.google.gerrit.client.ui.Screen;
 import com.google.gerrit.common.data.PatchScript;
 import com.google.gerrit.common.data.PatchSetDetail;
@@ -112,6 +112,7 @@
 
   private CheckBox reviewedCheckBox;
   private FlowPanel reviewedPanel;
+  private InlineHyperlink reviewedLink;
   private HistoryTable historyTable;
   private FlowPanel topPanel;
   private FlowPanel contentPanel;
@@ -131,7 +132,9 @@
 
   /** Keys that cause an action on this screen */
   private KeyCommandSet keysNavigation;
+  private KeyCommandSet keysAction;
   private HandlerRegistration regNavigation;
+  private HandlerRegistration regAction;
   private boolean intralineFailure;
 
   /**
@@ -193,13 +196,6 @@
     Anchor reviewedAnchor = new Anchor("");
     SafeHtml.set(reviewedAnchor, text);
 
-    reviewedAnchor.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(ClickEvent event) {
-        setReviewedByCurrentUser(true);
-      }
-    });
-
     final PatchValidator unreviewedValidator = new PatchValidator() {
       public boolean isValid(Patch patch) {
         return !patch.isReviewedByCurrentUser();
@@ -212,25 +208,20 @@
 
     if (nextUnreviewedPatchIndex > -1) {
       // Create invisible patch link to change page
-      final PatchLink reviewedLink =
+      reviewedLink =
           fileList.createLink(nextUnreviewedPatchIndex, getPatchScreenType(),
               null, null);
       reviewedLink.setText("");
-      reviewedAnchor.addClickHandler(new ClickHandler() {
-        @Override
-        public void onClick(ClickEvent event) {
-          reviewedLink.go();
-        }
-      });
     } else {
-      final ChangeLink upLink = new ChangeLink("", patchKey.getParentKey());
-      reviewedAnchor.addClickHandler(new ClickHandler() {
-        @Override
-        public void onClick(ClickEvent event) {
-          upLink.go();
-        }
-      });
+      reviewedLink = new ChangeLink("", patchKey.getParentKey());
     }
+    reviewedAnchor.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        setReviewedByCurrentUser(true);
+        reviewedLink.go();
+      }
+    });
 
     return reviewedAnchor;
   }
@@ -310,6 +301,14 @@
     keysNavigation.add(new UpToChangeCommand(patchKey.getParentKey(), 0, 'u'));
     keysNavigation.add(new FileListCmd(0, 'f', PatchUtil.C.fileList()));
 
+    if (Gerrit.isSignedIn()) {
+      keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
+      keysAction
+          .add(new ToggleReviewedCmd(0, 'm', PatchUtil.C.toggleReviewed()));
+      keysAction.add(new MarkAsReviewedAndGoToNextCmd(0, 'M', PatchUtil.C
+          .markAsReviewedAndGoToNext()));
+    }
+
     historyTable = new HistoryTable(this);
 
     commitMessageBlock = new CommitMessageBlock();
@@ -393,6 +392,10 @@
       regNavigation.removeHandler();
       regNavigation = null;
     }
+    if (regAction != null) {
+      regAction.removeHandler();
+      regAction = null;
+    }
     super.onUnload();
   }
 
@@ -405,6 +408,13 @@
       regNavigation = null;
     }
     regNavigation = GlobalKey.add(this, keysNavigation);
+    if (regAction != null) {
+      regAction.removeHandler();
+      regAction = null;
+    }
+    if (keysAction != null) {
+      regAction = GlobalKey.add(this, keysAction);
+    }
   }
 
   protected abstract AbstractPatchContentTable createContentTable();
@@ -603,4 +613,31 @@
       p.open();
     }
   }
+
+  public class ToggleReviewedCmd extends KeyCommand {
+    public ToggleReviewedCmd(int mask, int key, String help) {
+      super(mask, key, help);
+    }
+
+    @Override
+    public void onKeyPress(final KeyPressEvent event) {
+      final boolean isReviewed = !reviewedCheckBox.getValue();
+      reviewedCheckBox.setValue(isReviewed);
+      setReviewedByCurrentUser(isReviewed);
+    }
+  }
+
+  public class MarkAsReviewedAndGoToNextCmd extends KeyCommand {
+    public MarkAsReviewedAndGoToNextCmd(int mask, int key, String help) {
+      super(mask, key, help);
+    }
+
+    @Override
+    public void onKeyPress(final KeyPressEvent event) {
+      if (reviewedLink != null) {
+        setReviewedByCurrentUser(true);
+        reviewedLink.go();
+      }
+    }
+  }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java
index 5dd4e1f..5d4207f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java
@@ -21,16 +21,18 @@
 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.dom.client.SpanElement;
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Style.Display;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.resources.client.CssResource;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.ui.Anchor;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.HTMLPanel;
-import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Image;
 import com.google.gwtorm.client.KeyUtil;
 
 import java.util.LinkedList;
@@ -46,6 +48,8 @@
     String selected();
 
     String hidden();
+
+    String downloadLink();
   }
 
   public enum Side {
@@ -68,7 +72,7 @@
   BoxStyle style;
 
   @UiField
-  SpanElement sideMarker;
+  DivElement sideMarker;
 
   public PatchSetSelectBox(Side side, final PatchScreen.Type type) {
     this.side = side;
@@ -86,14 +90,24 @@
     this.idActive = (side == Side.A) ? idSideA : idSideB;
     this.links = new LinkedList<Anchor>();
 
+    linkPanel.clear();
+
     if (screenType == PatchScreen.Type.UNIFIED) {
       sideMarker.setInnerText((side == Side.A) ? "(-)" : "(+)");
+    } else {
+      sideMarker.getStyle().setDisplay(Display.NONE);
     }
 
+    Anchor baseLink = null;
     if (detail.getInfo().getParents().size() > 1) {
-      addLink(PatchUtil.C.patchBaseAutoMerge(), null);
+      baseLink = createLink(PatchUtil.C.patchBaseAutoMerge(), null);
     } else {
-      addLink(PatchUtil.C.patchBase(), null);
+      baseLink = createLink(PatchUtil.C.patchBase(), null);
+    }
+
+    links.add(baseLink);
+    if (screenType == PatchScreen.Type.UNIFIED || side == Side.A) {
+      linkPanel.add(baseLink);
     }
 
     if (side == Side.B) {
@@ -102,7 +116,9 @@
 
     for (Patch patch : script.getHistory()) {
       PatchSet.Id psId = patch.getKey().getParentKey();
-      addLink(Integer.toString(psId.get()), psId);
+      Anchor anchor = createLink(Integer.toString(psId.get()), psId);
+      links.add(anchor);
+      linkPanel.add(anchor);
     }
 
     if (idActive == null && side == Side.A) {
@@ -111,14 +127,13 @@
       links.get(idActive.get()).setStyleName(style.selected());
     }
 
-    Anchor downloadLink = getDownloadLink();
+    Anchor downloadLink = createDownloadLink();
     if (downloadLink != null) {
-      linkPanel.add(new Label(" - "));
       linkPanel.add(downloadLink);
     }
   }
 
-  private void addLink(String label, final PatchSet.Id id) {
+  private Anchor createLink(String label, final PatchSet.Id id) {
     final Anchor anchor = new Anchor(label);
     anchor.addClickHandler(new ClickHandler() {
       @Override
@@ -143,11 +158,10 @@
 
     });
 
-    links.add(anchor);
-    linkPanel.add(anchor);
+    return anchor;
   }
 
-  private Anchor getDownloadLink() {
+  private Anchor createDownloadLink() {
     boolean isCommitMessage = Patch.COMMIT_MSG.equals(script.getNewName());
 
     if (isCommitMessage || (side == Side.A && 0 >= script.getA().size())
@@ -161,8 +175,14 @@
     String sideURL = (side == Side.A) ? "1" : "0";
     final String base = GWT.getHostPageBaseURL() + "cat/";
 
-    final Anchor anchor = new Anchor(PatchUtil.C.download());
+    Image image = new Image(Gerrit.RESOURCES.downloadIcon());
+
+    final Anchor anchor = new Anchor();
     anchor.setHref(base + KeyUtil.encode(key.toString()) + "^" + sideURL);
+    anchor.setTitle(PatchUtil.C.download());
+    anchor.setStyleName(style.downloadLink());
+    DOM.insertBefore(anchor.getElement(), image.getElement(),
+        DOM.getFirstChild(anchor.getElement()));
 
     return anchor;
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml
index 2c4bd5d..2fd183c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml
@@ -28,18 +28,21 @@
 
     .wrapper {
       width: 100%;
+      text-align: center;
+      font-size: 0; /* inline-block spacing fix */
     }
 
-    .patchSetLabel {
-      font-weight: bold;
+    .linkPanel {
+      display: inline-block;
     }
 
     .linkPanel > div {
       display: inline-block;
-      padding: 3px;
+      float: left;
     }
 
     .linkPanel {
+      overflow: hidden; /* div clear fix */
       font-size: 12px;
     }
 
@@ -47,6 +50,27 @@
       padding: 3px;
       display: inline-block;
       text-decoration: none;
+      float: left;
+    }
+
+    .patchSetLabel {
+      font-weight: bold;
+      float: left;
+      padding: 3px;
+    }
+
+    .sideMarker {
+      padding: 3px;
+    }
+
+    .downloadLink {
+      float: left;
+      padding: 1px !important;
+      margin-left: 3px;
+    }
+
+    .downloadLink > a {
+      text-size: 0;
     }
 
     .selected {
@@ -56,6 +80,7 @@
 
     .sideMarker {
       font-family: monospace;
+      float: left;
     }
 
     .hidden {
@@ -64,7 +89,10 @@
   </ui:style>
 
   <g:HTMLPanel styleName='wrapper'>
-    <g:HTMLPanel styleName='{style.linkPanel}' ui:field='linkPanel'><span class='{style.patchSetLabel}'><ui:text from="{cons.patchSet}" /></span> <span class='{style.sideMarker}' ui:field='sideMarker'></span>: </g:HTMLPanel>
+    <g:HTMLPanel styleName='{style.linkPanel}' ui:field='linkPanel'>
+      <div class='{style.patchSetLabel}'><ui:text from="{cons.patchSet}" /></div>
+      <div class='{style.sideMarker}' ui:field='sideMarker'></div>
+    </g:HTMLPanel>
   </g:HTMLPanel>
 </ui:UiBinder>
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderSideBySide.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderSideBySide.ui.xml
index 424e6e5..d6fd717 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderSideBySide.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderSideBySide.ui.xml
@@ -26,6 +26,7 @@
       width: 100%;
       background-color: trimColor;
       overflow: hidden;
+      font-size: 0; /* inline-block spacing fix */
     }
 
     .wrapper .box {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderUnified.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderUnified.ui.xml
index e26e96a..24acfa3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderUnified.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderUnified.ui.xml
@@ -24,6 +24,7 @@
     .wrapper {
       width: 100%;
       background-color: trimColor;
+      font-size: 0; /* inline-block spacing fix */
     }
 
     .wrapper .box {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
index c422f6d..69a283a 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
@@ -19,6 +19,7 @@
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetAncestor;
 import com.google.gerrit.reviewdb.client.PatchSetInfo;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RevId;
@@ -31,17 +32,16 @@
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.patch.AddReviewer;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
-import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
-import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.revwalk.RevCommit;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -81,36 +81,56 @@
 
   @Override
   protected Change.Id updateProjectConfig(ProjectConfig config, MetaDataUpdate md)
-      throws IOException, NoSuchProjectException, ConfigInvalidException, OrmException {
-    int nextChangeId = db.nextChangeId();
-    PatchSet.Id patchSetId = new PatchSet.Id(new Change.Id(nextChangeId), 1);
-    final PatchSet ps = new PatchSet(patchSetId);
+      throws IOException, OrmException {
+    Change.Id changeId = new Change.Id(db.nextChangeId());
+    PatchSet ps = new PatchSet(new PatchSet.Id(changeId, 1));
     RevCommit commit = config.commitToNewRef(md, ps.getRefName());
     if (commit.getId().equals(base)) {
       return null;
     }
-    Change.Key changeKey = new Change.Key("I" + commit.name());
-    final Change change =
-        new Change(changeKey, new Change.Id(nextChangeId), user.getAccountId(),
-            new Branch.NameKey(config.getProject().getNameKey(),
-                GitRepositoryManager.REF_CONFIG));
+
+    Change change = new Change(
+        new Change.Key("I" + commit.name()),
+        changeId,
+        user.getAccountId(),
+        new Branch.NameKey(
+            config.getProject().getNameKey(),
+            GitRepositoryManager.REF_CONFIG));
     change.nextPatchSetId();
 
     ps.setCreatedOn(change.getCreatedOn());
-    ps.setUploader(user.getAccountId());
+    ps.setUploader(change.getOwner());
     ps.setRevision(new RevId(commit.name()));
 
-    db.patchSets().insert(Collections.singleton(ps));
-
-    final PatchSetInfo info = patchSetInfoFactory.get(commit, ps.getId());
+    PatchSetInfo info = patchSetInfoFactory.get(commit, ps.getId());
     change.setCurrentPatchSet(info);
     ChangeUtil.updated(change);
 
-    db.changes().insert(Collections.singleton(change));
+    db.changes().beginTransaction(changeId);
+    try {
+      insertAncestors(ps.getId(), commit);
+      db.patchSets().insert(Collections.singleton(ps));
+      db.changes().insert(Collections.singleton(change));
+      addProjectOwnersAsReviewers(changeId);
+      db.commit();
+    } finally {
+      db.rollback();
+    }
+    return changeId;
+  }
 
-    addProjectOwnersAsReviewers(change.getId());
+  private void insertAncestors(PatchSet.Id id, RevCommit src)
+      throws OrmException {
+    final int cnt = src.getParentCount();
+    List<PatchSetAncestor> toInsert = new ArrayList<PatchSetAncestor>(cnt);
+    for (int p = 0; p < cnt; p++) {
+      PatchSetAncestor a;
 
-    return change.getId();
+      a = new PatchSetAncestor(new PatchSetAncestor.Id(id, p + 1));
+      a.setAncestorRevision(new RevId(src.getParent(p).name()));
+      toInsert.add(a);
+    }
+    db.patchSetAncestors().insert(toInsert);
   }
 
   private void addProjectOwnersAsReviewers(final Change.Id changeId) {
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
index a5373b8..1a5468c 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
@@ -249,7 +249,7 @@
     range.lines = lines;
 
     SparseFileContent r = new SparseFileContent();
-    r.setSize(size());
+    r.setSize(lines.size());
     r.setMissingNewlineAtEnd(isMissingNewlineAtEnd());
     r.setPath(getPath());
     r.ranges.add(range);
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 3868710..94b2169 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
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server;
 
+import com.google.common.collect.Sets;
 import com.google.gerrit.common.ChangeHookRunner;
 import com.google.gerrit.common.ChangeHooks;
 import com.google.gerrit.reviewdb.client.Account;
@@ -38,7 +39,6 @@
 import com.google.gerrit.server.mail.ReplyToChangeSender;
 import com.google.gerrit.server.mail.RevertedSender;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
-import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
@@ -68,6 +68,7 @@
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -196,13 +197,15 @@
    * Rebases a commit
    *
    * @param git Repository to find commits in
+   * @param inserter inserter to handle new trees and blobs.
    * @param original The commit to rebase
    * @param base Base to rebase against
    * @return CommitBuilder the newly rebased commit
    * @throws IOException Merged failed
    */
-  public static CommitBuilder rebaseCommit(Repository git, RevCommit original,
-      RevCommit base, PersonIdent committerIdent) throws IOException {
+  public static CommitBuilder rebaseCommit(Repository git,
+      final ObjectInserter inserter, RevCommit original, RevCommit base,
+      PersonIdent committerIdent) throws IOException {
 
     if (original.getParentCount() == 0) {
       throw new IOException(
@@ -222,6 +225,20 @@
     }
 
     final ThreeWayMerger merger = MergeStrategy.RESOLVE.newMerger(git, true);
+    merger.setObjectInserter(new ObjectInserter.Filter() {
+      @Override
+      protected ObjectInserter delegate() {
+        return inserter;
+      }
+
+      @Override
+      public void flush() {
+      }
+
+      @Override
+      public void release() {
+      }
+    });
     merger.setBase(parentCommit);
     merger.merge(original, base);
 
@@ -251,7 +268,7 @@
       final ApprovalsUtil approvalsUtil) throws NoSuchChangeException,
       EmailException, OrmException, MissingObjectException,
       IncorrectObjectTypeException, IOException,
-      PatchSetInfoNotAvailableException, InvalidChangeOperationException {
+      InvalidChangeOperationException {
 
     final Change.Id changeId = patchSetId.getParentKey();
     final ChangeControl changeControl =
@@ -319,104 +336,118 @@
           branchTipCommit = revWalk.parseCommit(destRef.getObjectId());
         }
 
-        final RevCommit originalCommit =
-            revWalk.parseCommit(ObjectId.fromString(originalPatchSet
-                .getRevision().get()));
-
-        CommitBuilder rebasedCommitBuilder =
-            rebaseCommit(git, originalCommit, branchTipCommit, myIdent);
-
+        final RevCommit rebasedCommit;
         final ObjectInserter oi = git.newObjectInserter();
-        final ObjectId rebasedCommitId;
         try {
-          rebasedCommitId = oi.insert(rebasedCommitBuilder);
+          ObjectId oldId = ObjectId.fromString(originalPatchSet.getRevision().get());
+          ObjectId newId = oi.insert(rebaseCommit(
+              git, oi, revWalk.parseCommit(oldId), branchTipCommit, myIdent));
           oi.flush();
+          rebasedCommit = revWalk.parseCommit(newId);
         } finally {
           oi.release();
         }
 
-        Change updatedChange =
-            db.changes().atomicUpdate(changeId, new AtomicUpdate<Change>() {
-              @Override
-              public Change update(Change change) {
-                if (change.getStatus().isOpen()) {
-                  change.nextPatchSetId();
-                  return change;
-                } else {
-                  return null;
-                }
-              }
-            });
+        change.nextPatchSetId();
+        final PatchSet newPatchSet = new PatchSet(change.currPatchSetId());
+        newPatchSet.setCreatedOn(new Timestamp(System.currentTimeMillis()));
+        newPatchSet.setUploader(user.getAccountId());
+        newPatchSet.setRevision(new RevId(rebasedCommit.name()));
 
-        if (updatedChange == null) {
-          throw new InvalidChangeOperationException("Change is closed: "
-              + change.toString());
-        } else {
-          change = updatedChange;
-        }
-
-        final PatchSet rebasedPatchSet = new PatchSet(change.currPatchSetId());
-        rebasedPatchSet.setCreatedOn(change.getCreatedOn());
-        rebasedPatchSet.setUploader(user.getAccountId());
-        rebasedPatchSet.setRevision(new RevId(rebasedCommitId.getName()));
-
-        insertAncestors(db, rebasedPatchSet.getId(),
-            revWalk.parseCommit(rebasedCommitId));
-
-        db.patchSets().insert(Collections.singleton(rebasedPatchSet));
         final PatchSetInfo info =
-            patchSetInfoFactory.get(db, rebasedPatchSet.getId());
+            patchSetInfoFactory.get(rebasedCommit, newPatchSet.getId());
 
-        change =
-            db.changes().atomicUpdate(change.getId(),
-                new AtomicUpdate<Change>() {
-                  @Override
-                  public Change update(Change change) {
-                    change.setCurrentPatchSet(info);
-                    ChangeUtil.updated(change);
-                    return change;
-                  }
-                });
-
-        final RefUpdate ru = git.updateRef(rebasedPatchSet.getRefName());
-        ru.setNewObjectId(rebasedCommitId);
+        RefUpdate ru = git.updateRef(newPatchSet.getRefName());
+        ru.setExpectedOldObjectId(ObjectId.zeroId());
+        ru.setNewObjectId(rebasedCommit);
         ru.disableRefLog();
         if (ru.update(revWalk) != RefUpdate.Result.NEW) {
-          throw new IOException("Failed to create ref "
-              + rebasedPatchSet.getRefName() + " in " + git.getDirectory()
-              + ": " + ru.getResult());
+          throw new IOException(String.format(
+              "Failed to create ref %s in %s: %s", newPatchSet.getRefName(),
+              change.getDest().getParentKey().get(), ru.getResult()));
         }
-
         replication.fire(change.getProject(), ru.getName());
 
-        List<PatchSetApproval> patchSetApprovals = approvalsUtil.copyVetosToLatestPatchSet(change);
+        final Set<Account.Id> oldReviewers = Sets.newHashSet();
+        final Set<Account.Id> oldCC = Sets.newHashSet();
+        db.changes().beginTransaction(change.getId());
+        try {
+          Change updatedChange;
 
-        final Set<Account.Id> oldReviewers = new HashSet<Account.Id>();
-        final Set<Account.Id> oldCC = new HashSet<Account.Id>();
-
-        for (PatchSetApproval a : patchSetApprovals) {
-          if (a.getValue() != 0) {
-            oldReviewers.add(a.getAccountId());
+          updatedChange = db.changes().atomicUpdate(changeId,
+              new AtomicUpdate<Change>() {
+                @Override
+                public Change update(Change change) {
+                  if (change.getStatus().isOpen()) {
+                    change.updateNumberOfPatchSets(newPatchSet.getPatchSetId());
+                    return change;
+                  } else {
+                    return null;
+                  }
+                }
+              });
+          if (updatedChange != null) {
+            change = updatedChange;
           } else {
-            oldCC.add(a.getAccountId());
+            throw new InvalidChangeOperationException(
+                String.format("Change %s is closed", change.getId()));
           }
-        }
 
-        final ChangeMessage cmsg =
-            new ChangeMessage(new ChangeMessage.Key(changeId,
-                ChangeUtil.messageUUID(db)), user.getAccountId(), patchSetId);
-        cmsg.setMessage("Patch Set " + patchSetId.get() + ": Rebased");
-        db.changeMessages().insert(Collections.singleton(cmsg));
+          insertAncestors(db, newPatchSet.getId(), rebasedCommit);
+          db.patchSets().insert(Collections.singleton(newPatchSet));
+          updatedChange = db.changes().atomicUpdate(changeId,
+              new AtomicUpdate<Change>() {
+                @Override
+                public Change update(Change change) {
+                  if (change.getStatus().isClosed()) {
+                    return null;
+                  }
+                  if (!change.currentPatchSetId().equals(patchSetId)) {
+                    return null;
+                  }
+                  if (change.getStatus() != Change.Status.DRAFT) {
+                    change.setStatus(Change.Status.NEW);
+                  }
+                  change.setLastSha1MergeTested(null);
+                  change.setCurrentPatchSet(info);
+                  ChangeUtil.updated(change);
+                  return change;
+                }
+              });
+          if (updatedChange != null) {
+            change = updatedChange;
+          } else {
+            throw new InvalidChangeOperationException(
+                String.format("Change %s was modified", change.getId()));
+          }
+
+          for (PatchSetApproval a : approvalsUtil.copyVetosToLatestPatchSet(change)) {
+            if (a.getValue() != 0) {
+              oldReviewers.add(a.getAccountId());
+            } else {
+              oldCC.add(a.getAccountId());
+            }
+          }
+
+          final ChangeMessage cmsg =
+              new ChangeMessage(new ChangeMessage.Key(changeId,
+                  ChangeUtil.messageUUID(db)), user.getAccountId(), patchSetId);
+          cmsg.setMessage("Patch Set " + patchSetId.get() + ": Rebased");
+          db.changeMessages().insert(Collections.singleton(cmsg));
+          db.commit();
+        } finally {
+          db.rollback();
+        }
 
         final ReplacePatchSetSender cm =
             rebasedPatchSetSenderFactory.create(change);
         cm.setFrom(user.getAccountId());
-        cm.setPatchSet(rebasedPatchSet);
+        cm.setPatchSet(newPatchSet);
         cm.addReviewers(oldReviewers);
         cm.addExtraCC(oldCC);
         cm.send();
 
-        hooks.doPatchsetCreatedHook(change, rebasedPatchSet, db);
+        hooks.doPatchsetCreatedHook(change, newPatchSet, db);
       } finally {
         revWalk.release();
       }
@@ -432,9 +463,7 @@
       final PatchSetInfoFactory patchSetInfoFactory,
       final GitReferenceUpdated replication, PersonIdent myIdent)
       throws NoSuchChangeException, EmailException, OrmException,
-      MissingObjectException, IncorrectObjectTypeException, IOException,
-      PatchSetInfoNotAvailableException {
-
+      MissingObjectException, IncorrectObjectTypeException, IOException {
     final Change.Id changeId = patchSetId.getParentKey();
     final PatchSet patch = db.patchSets().get(patchSetId);
     if (patch == null) {
@@ -446,7 +475,7 @@
       git = gitManager.openRepository(db.changes().get(changeId).getProject());
     } catch (RepositoryNotFoundException e) {
       throw new NoSuchChangeException(changeId, e);
-    };
+    }
 
     final RevWalk revWalk = new RevWalk(git);
     try {
@@ -459,54 +488,62 @@
       RevCommit parentToCommitToRevert = commitToRevert.getParent(0);
       revWalk.parseHeaders(parentToCommitToRevert);
 
-      CommitBuilder revertCommit = new CommitBuilder();
-      revertCommit.addParentId(commitToRevert);
-      revertCommit.setTreeId(parentToCommitToRevert.getTree());
-      revertCommit.setAuthor(authorIdent);
-      revertCommit.setCommitter(myIdent);
+      CommitBuilder revertCommitBuilder = new CommitBuilder();
+      revertCommitBuilder.addParentId(commitToRevert);
+      revertCommitBuilder.setTreeId(parentToCommitToRevert.getTree());
+      revertCommitBuilder.setAuthor(authorIdent);
+      revertCommitBuilder.setCommitter(myIdent);
 
       final ObjectId computedChangeId =
           ChangeIdUtil.computeChangeId(parentToCommitToRevert.getTree(),
               commitToRevert, authorIdent, myIdent, message);
-      revertCommit.setMessage(ChangeIdUtil.insertId(message, computedChangeId, true));
+      revertCommitBuilder.setMessage(ChangeIdUtil.insertId(message, computedChangeId, true));
 
-      final ObjectInserter oi = git.newObjectInserter();;
-      ObjectId id;
+      RevCommit revertCommit;
+      final ObjectInserter oi = git.newObjectInserter();
       try {
-        id = oi.insert(revertCommit);
+        ObjectId id = oi.insert(revertCommitBuilder);
         oi.flush();
+        revertCommit = revWalk.parseCommit(id);
       } finally {
         oi.release();
       }
 
-      Change.Key changeKey = new Change.Key("I" + computedChangeId.name());
-      final Change change =
-          new Change(changeKey, new Change.Id(db.nextChangeId()),
-              user.getAccountId(), db.changes().get(changeId).getDest());
+      final Change change = new Change(
+          new Change.Key("I" + computedChangeId.name()),
+          new Change.Id(db.nextChangeId()),
+          user.getAccountId(),
+          db.changes().get(changeId).getDest());
       change.nextPatchSetId();
 
       final PatchSet ps = new PatchSet(change.currPatchSetId());
       ps.setCreatedOn(change.getCreatedOn());
-      ps.setUploader(user.getAccountId());
-      ps.setRevision(new RevId(id.getName()));
+      ps.setUploader(change.getOwner());
+      ps.setRevision(new RevId(revertCommit.name()));
 
-      db.patchSets().insert(Collections.singleton(ps));
-
-      final PatchSetInfo info =
-          patchSetInfoFactory.get(revWalk.parseCommit(id), ps.getId());
-      change.setCurrentPatchSet(info);
+      change.setCurrentPatchSet(patchSetInfoFactory.get(revertCommit, ps.getId()));
       ChangeUtil.updated(change);
-      db.changes().insert(Collections.singleton(change));
 
       final RefUpdate ru = git.updateRef(ps.getRefName());
-      ru.setNewObjectId(id);
+      ru.setExpectedOldObjectId(ObjectId.zeroId());
+      ru.setNewObjectId(revertCommit);
       ru.disableRefLog();
       if (ru.update(revWalk) != RefUpdate.Result.NEW) {
-        throw new IOException("Failed to create ref " + ps.getRefName()
-            + " in " + git.getDirectory() + ": " + ru.getResult());
+        throw new IOException(String.format(
+            "Failed to create ref %s in %s: %s", ps.getRefName(),
+            change.getDest().getParentKey().get(), ru.getResult()));
       }
-      replication.fire(db.changes().get(changeId).getProject(),
-          ru.getName());
+      replication.fire(change.getProject(), ru.getName());
+
+      db.changes().beginTransaction(change.getId());
+      try {
+        insertAncestors(db, ps.getId(), revertCommit);
+        db.patchSets().insert(Collections.singleton(ps));
+        db.changes().insert(Collections.singleton(change));
+        db.commit();
+      } finally {
+        db.rollback();
+      }
 
       final ChangeMessage cmsg =
           new ChangeMessage(new ChangeMessage.Key(changeId,
@@ -514,7 +551,7 @@
       final StringBuilder msgBuf =
           new StringBuilder("Patch Set " + patchSetId.get() + ": Reverted");
       msgBuf.append("\n\n");
-      msgBuf.append("This patchset was reverted in change: " + changeKey.get());
+      msgBuf.append("This patchset was reverted in change: " + change.getKey().get());
 
       cmsg.setMessage(msgBuf.toString());
       db.changeMessages().insert(Collections.singleton(cmsg));
@@ -596,7 +633,7 @@
   public static <T extends ReplyToChangeSender> void updatedChange(
       final ReviewDb db, final IdentifiedUser user, final Change change,
       final ChangeMessage cmsg, ReplyToChangeSender.Factory<T> senderFactory)
-      throws NoSuchChangeException, EmailException, OrmException {
+      throws OrmException {
     db.changeMessages().insert(Collections.singleton(cmsg));
 
     new ApprovalsUtil(db, null).syncChangeStatus(change);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index 9571f39..ccf7c2d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -613,10 +613,10 @@
       if (replace.inputCommand == newChange) {
         replaceCount++;
 
-        if (replace.cmd.getResult() == OK) {
+        if (replace.cmd != null && replace.cmd.getResult() == OK) {
           okToInsert++;
         }
-      } else if (replace.cmd.getResult() == OK) {
+      } else if (replace.cmd != null && replace.cmd.getResult() == OK) {
         try {
           if (replace.insertPatchSet().checkedGet() != null) {
             replace.inputCommand.setResult(OK);
@@ -856,7 +856,7 @@
       } else {
         errors.put(Error.UPDATE, ctl.getRefName());
       }
-      reject(cmd, "can not update the reference as a fast forward");
+      reject(cmd);
     }
   }
 
@@ -1318,6 +1318,9 @@
       final List<FooterLine> footerLines = commit.getFooterLines();
       for (final FooterLine footerLine : footerLines) {
         try {
+          if (ps.isDraft()) {
+            continue;
+          }
           if (isReviewer(footerLine)) {
             reviewers.add(toAccountId(footerLine.getValue().trim()));
           } else if (footerLine.matches(FooterKey.CC)) {
@@ -1406,7 +1409,7 @@
     }
 
     for (ReplaceRequest req : replaceByChange.values()) {
-      if (req.inputCommand.getResult() == NOT_ATTEMPTED) {
+      if (req.inputCommand.getResult() == NOT_ATTEMPTED && req.cmd != null) {
         batch.addCommand(req.cmd);
       }
     }
@@ -1414,7 +1417,7 @@
     if (newChange != null && newChange.getResult() != NOT_ATTEMPTED) {
       // Cancel creations tied to refs/for/ or refs/drafts/ command.
       for (ReplaceRequest req : replaceByChange.values()) {
-        if (req.inputCommand == newChange) {
+        if (req.inputCommand == newChange && req.cmd != null) {
           req.cmd.setResult(Result.REJECTED_OTHER_REASON, "aborted");
         }
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
index 44536e2..e9c5536 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
@@ -254,6 +254,8 @@
         RefUpdate ru = db.updateRef(refName);
         ru.setExpectedOldObjectId(ObjectId.zeroId());
         ru.setNewObjectId(src);
+        ru.disableRefLog();
+        inserter.flush();
         RefUpdate.Result result = ru.update();
         switch (result) {
           case NEW:
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ListChanges.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ListChanges.java
index a900175..f0ed66a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ListChanges.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ListChanges.java
@@ -349,6 +349,10 @@
     }
 
     PatchSet ps = cd.currentPatchSet(db);
+    if (ps == null) {
+      return Collections.emptyMap();
+    }
+
     Map<String, LabelInfo> labels = Maps.newLinkedHashMap();
     for (SubmitRecord rec : ctl.canSubmit(db.get(), ps, cd, true, false)) {
       if (rec.labels == null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestScopePropagator.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestScopePropagator.java
index e465247..7728d6f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestScopePropagator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestScopePropagator.java
@@ -45,19 +45,16 @@
     return new Callable<T>() {
       @Override
       public T call() throws Exception {
-        if (threadLocal.get() != null) {
-          // This is consistent with the Guice ServletScopes.continueRequest()
-          // behavior.
-          throw new IllegalStateException("Cannot continue request, "
-              + "thread already has request in progress. A new thread must "
-              + "be used to propagate the request scope context.");
-        }
-
+        C old = threadLocal.get();
         threadLocal.set(ctx);
         try {
           return callable.call();
         } finally {
-          threadLocal.remove();
+          if (old != null) {
+            threadLocal.set(old);
+          } else {
+            threadLocal.remove();
+          }
         }
       }
     };