Merge "CM3: Add support for dark themes"
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index c59f0e9..2e9c83c 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -424,6 +424,14 @@
 plugins will make use of the setXXX methods on the ReceivePack to
 set additional properties on it.
 
+[[post-receive-hook]]
+== Post Receive-Pack Hooks
+
+Plugins may register PostReceiveHook instances in order to get
+notified when JGit successfully receives a pack. This may be useful
+for those plugins which would like to monitor changes in Git
+repositories.
+
 [[ssh]]
 == SSH Commands
 
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 036392c..0708278 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -3083,6 +3083,8 @@
 |`disliked`    |optional|One user who disliked this label on the change
 (voted negatively, but not the minimum value) as an
 link:rest-api-accounts.html#account-info[AccountInfo] entity.
+|`blocking`    |optional|If `true`, the label blocks submit operation.
+If not set, the default is false.
 |`value`       |optional|The voting value of the user who
 recommended/disliked this label on the change if it is not
 "`+1`"/"`-1`".
diff --git a/ReleaseNotes/ReleaseNotes-2.8.2.txt b/ReleaseNotes/ReleaseNotes-2.8.2.txt
index 67a1135..9b72a77 100644
--- a/ReleaseNotes/ReleaseNotes-2.8.2.txt
+++ b/ReleaseNotes/ReleaseNotes-2.8.2.txt
@@ -66,12 +66,46 @@
 an internal server error.
 
 * link:https://code.google.com/p/gerrit/issues/detail?id=2331[Issue 2331]:
-Make sure change-merged event contains correct patch set number.
+Make sure `change-merged` event contains correct patch set number.
 +
 When a change is submitted with the cherry-pick strategy, or when the
 change is rebased with the "rebase if necessary" strategy, a new patch
 set is created.  The newly created patch set was not being set in the
-change-merged event.
+`change-merged` event.
+
+* Guard against `diff.mnemonicprefix` in `commit-msg` hook.
++
+When `diff.mnemonicprefix` was enabled in the git config, committing
+changes with `git commit -v` caused the diff to be included in the
+generated commit message.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2453[Issue 2453]:
+Fix submit rule evaluation for non blocking labels.
++
+Putting a negative score on a label configured as `NoBlock` was causing
+the submit button to be disabled.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2331[Issue 2331]:
+Allow to create branch with new commits.
++
+Branches could not be created with a new commit which is not on other branches
+already.
+
+* Fix incompatibility between "Rebase if Necessary" and "copy scores".
++
+When a project was set up with "Rebase if Necessary", one of its labels had
+`copyAllScoresOnTrivialRebase` or `copyMaxScore`, and a change that actually
+needed a trivial rebase was submitted, Gerrit first rebased the change, and in
+the process copied the approval for the label.  It then copied all the
+approvals, including the one already copied, which resulted in a constraint
+violation on the database.
+
+* Add `Implementation-Vendor` default manifest entry for plugins.
++
+In buck, the `java_binary` rule merges manifest entries from dependent JARs
+unless the input JAR possesses these entries itself.  This was causing some
+plugins to display the wrong vendor information if they had dependency on
+another JAR file that provided a `Implementation-Vendor` value.
 
 * Remove dependency on joda time library in gerrit launcher.
 +
@@ -141,6 +175,19 @@
 have a wide display, and better fit on more narrow displays by
 splitting the available width at 50%.
 
+* Fire `comment-added` stream event even when mail notification is not sent.
++
+Unchecking the "and send email" option on the change screen prevented the
+`comment-added` event from being sent to the event stream.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2493[Issue 2493]:
+Set uploader to current user in `patchset-created` event upon rebasing
+a change in the UI.
++
+When a change was rebased from the change screen, the `uploader` field
+of the `patchset-created` event was incorrectly set to the original
+change uploader, rather than the user that performed the rebase.
+
 ssh
 ---
 
@@ -170,6 +217,8 @@
 
 * Fix aliasing of SSH commands.
 
+* link:https://code.google.com/p/gerrit/issues/detail?id=2515[Issue 2515]:
+Fix internal server error when updating an existing label with `gerrit review`.
 
 Replication Plugin
 ------------------
@@ -221,3 +270,7 @@
 
 * Add a link from the plugin documentation to the validation listeners API
 documentation.
+
+* Remove double border around code snippets.
+
+* Add border around tables.
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 6e6ef37..5c5746b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -22,6 +22,7 @@
 import com.google.common.base.Joiner;
 import com.google.common.primitives.Chars;
 import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.RevisionApi;
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.common.ListChangesOption;
 import com.google.gerrit.extensions.restapi.RestApiException;
@@ -196,4 +197,10 @@
   protected static Gson newGson() {
     return OutputFormat.JSON_COMPACT.newGson();
   }
+
+  protected RevisionApi revision(PushOneCommit.Result r) throws Exception {
+    return gApi.changes()
+        .id(r.getChangeId())
+        .current();
+  }
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
new file mode 100644
index 0000000..f38ac89
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
@@ -0,0 +1,153 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.server.project;
+
+import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
+import static com.google.gerrit.server.project.Util.category;
+import static com.google.gerrit.server.project.Util.grant;
+import static com.google.gerrit.server.project.Util.value;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.common.data.LabelType;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.LabelInfo;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.inject.Inject;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@NoHttpd
+public class CustomLabelIT extends AbstractDaemonTest {
+
+  @Inject
+  private ProjectCache projectCache;
+
+  @Inject
+  private AllProjectsName allProjects;
+
+  @Inject
+  private MetaDataUpdate.Server metaDataUpdateFactory;
+
+  private final LabelType Q = category("CustomLabel",
+      value(1, "Positive"),
+      value(0, "No score"),
+      value(-1, "Negative"));
+
+  @Before
+  public void setUp() throws Exception {
+    ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+    AccountGroup.UUID anonymousUsers =
+        SystemGroupBackend.getGroup(ANONYMOUS_USERS).getUUID();
+    grant(cfg, Permission.forLabel(Q.getName()), -1, 1, anonymousUsers,
+        "refs/heads/*");
+    saveProjectConfig(cfg);
+  }
+
+  @Test
+  public void customLabelNoOp_NegativeVoteNotBlock() throws Exception {
+    Q.setFunctionName("NoOp");
+    saveLabelConfig();
+    PushOneCommit.Result r = createChange();
+    revision(r).review(new ReviewInput().label(Q.getName(), -1));
+    ChangeInfo c = get(r.getChangeId());
+    LabelInfo q = c.labels.get(Q.getName());
+    assertEquals(1, q.all.size());
+    assertNotNull(q.rejected);
+    assertNull(q.blocking);
+  }
+
+  @Test
+  public void customLabelNoBlock_NegativeVoteNotBlock() throws Exception {
+    Q.setFunctionName("NoBlock");
+    saveLabelConfig();
+    PushOneCommit.Result r = createChange();
+    revision(r).review(new ReviewInput().label(Q.getName(), -1));
+    ChangeInfo c = get(r.getChangeId());
+    LabelInfo q = c.labels.get(Q.getName());
+    assertEquals(1, q.all.size());
+    assertNotNull(q.rejected);
+    assertNull(q.blocking);
+  }
+
+  @Test
+  public void customLabelMaxNoBlock_NegativeVoteNotBlock() throws Exception {
+    Q.setFunctionName("MaxNoBlock");
+    saveLabelConfig();
+    PushOneCommit.Result r = createChange();
+    revision(r).review(new ReviewInput().label(Q.getName(), -1));
+    ChangeInfo c = get(r.getChangeId());
+    LabelInfo q = c.labels.get(Q.getName());
+    assertEquals(1, q.all.size());
+    assertNotNull(q.rejected);
+    assertNull(q.blocking);
+  }
+
+  @Test
+  public void customLabelAnyWithBlock_NegativeVoteBlock() throws Exception {
+    Q.setFunctionName("AnyWithBlock");
+    saveLabelConfig();
+    PushOneCommit.Result r = createChange();
+    revision(r).review(new ReviewInput().label(Q.getName(), -1));
+    ChangeInfo c = get(r.getChangeId());
+    LabelInfo q = c.labels.get(Q.getName());
+    assertEquals(1, q.all.size());
+    assertNull(q.disliked);
+    assertNotNull(q.rejected);
+    assertTrue(q.blocking);
+  }
+
+  @Test
+  public void customLabelMaxWithBlock_NegativeVoteBlock() throws Exception {
+    saveLabelConfig();
+    PushOneCommit.Result r = createChange();
+    revision(r).review(new ReviewInput().label(Q.getName(), -1));
+    ChangeInfo c = get(r.getChangeId());
+    LabelInfo q = c.labels.get(Q.getName());
+    assertEquals(1, q.all.size());
+    assertNull(q.disliked);
+    assertNotNull(q.rejected);
+    assertTrue(q.blocking);
+  }
+
+  private void saveLabelConfig() throws Exception {
+    ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+    cfg.getLabelSections().put(Q.getName(), Q);
+    saveProjectConfig(cfg);
+  }
+
+  private void saveProjectConfig(ProjectConfig cfg) throws Exception {
+    MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
+    try {
+      cfg.commit(md);
+    } finally {
+      md.close();
+    }
+    projectCache.evict(allProjects);
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
index e94d8f3..a2dd8ec 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.acceptance.server.project;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.gerrit.extensions.common.ListChangesOption.DETAILED_LABELS;
 import static org.junit.Assert.assertEquals;
 
 import com.google.gerrit.acceptance.AbstractDaemonTest;
@@ -23,7 +22,6 @@
 import com.google.gerrit.acceptance.PushOneCommit;
 import com.google.gerrit.common.data.LabelType;
 import com.google.gerrit.extensions.api.changes.ReviewInput;
-import com.google.gerrit.extensions.api.changes.RevisionApi;
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.common.LabelInfo;
 import com.google.gerrit.server.config.AllProjectsName;
@@ -235,12 +233,6 @@
     }
   }
 
-  private RevisionApi revision(PushOneCommit.Result r) throws Exception {
-    return gApi.changes()
-        .id(r.getChangeId())
-        .current();
-  }
-
   private void merge(PushOneCommit.Result r) throws Exception {
     revision(r).review(ReviewInput.approve());
     revision(r).submit();
@@ -261,7 +253,7 @@
       throws Exception {
     // Don't use asserts from PushOneCommit so we can test the round-trip
     // through JSON instead of querying the DB directly.
-    ChangeInfo c = get(r.getChangeId(), DETAILED_LABELS);
+    ChangeInfo c = get(r.getChangeId());
     LabelInfo cr = c.labels.get("Code-Review");
     assertEquals(1, cr.all.size());
     assertEquals("Administrator", cr.all.get(0).name);
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
index 508fd7e..fd6008f 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
@@ -26,4 +26,5 @@
   public Map<String, String> values;
   public Short value;
   public Boolean optional;
+  public Boolean blocking;
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java
index 8048c4d..700c701 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java
@@ -75,7 +75,7 @@
     center.add(body);
     center.add(buttons);
 
-    setText(Gerrit.C.errorDialogTitle());
+    setText(Gerrit.C.errorTitle());
     addStyleName(Gerrit.RESOURCES.css().errorDialog());
     add(center);
 
@@ -155,8 +155,9 @@
     }
   }
 
-  public void setText(final String t) {
+  public ErrorDialog setText(final String t) {
     text.setText(t);
+    return this;
   }
 
   @Override
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 c0f91d3..2d20b98 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
@@ -29,8 +29,9 @@
   String registerDialogTitle();
   String loginTypeUnsupported();
 
-  String errorDialogTitle();
+  String errorTitle();
   String errorDialogContinue();
+  String warnTitle();
 
   String confirmationDialogOk();
   String confirmationDialogCancel();
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 27cc303..af530f4 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
@@ -10,8 +10,9 @@
 registerDialogTitle = Code Review - Register New Account
 loginTypeUnsupported = Sign in is not available.
 
-errorDialogTitle = Code Review - Error
+errorTitle = Code Review - Error
 errorDialogContinue = Continue
+warnTitle = Code Review - Warning
 
 confirmationDialogOk = OK
 confirmationDialogCancel = Cancel
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
index 1155b9b..b3f0f65 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
@@ -631,11 +631,21 @@
         if (allowedCommands.contains(DownloadCommand.CHECKOUT)
             || allowedCommands.contains(DownloadCommand.DEFAULT_DOWNLOADS)) {
           commands.add(cmdLinkfactory.new CloneCommandLink());
+          if (Gerrit.getConfig().getSshdAddress() != null && hasUserName()) {
+            commands.add(
+                cmdLinkfactory.new CloneWithCommitMsgHookCommandLink(getProjectKey()));
+          }
         }
       }
     }
   }
 
+  private static boolean hasUserName() {
+    return Gerrit.isSignedIn()
+        && Gerrit.getUserAccount().getUserName() != null
+        && Gerrit.getUserAccount().getUserName().length() > 0;
+  }
+
   private class LabeledWidgetsGrid extends FlexTable {
     private String labelSuffix;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
index a88edfa..2680347 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
@@ -126,10 +126,12 @@
             break;
           case REJECT:
           case IMPOSSIBLE:
-            if (current) {
-              statusText.setInnerText("Not " + name);
+            if (label.blocking()) {
+              if (current) {
+                statusText.setInnerText("Not " + name);
+              }
+              canSubmit = false;
             }
-            canSubmit = false;
             break;
           default:
             break;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
index bc752cf..bfe70b8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
@@ -160,6 +160,7 @@
     public final native String value_text(String n) /*-{ return this.values[n]; }-*/;
 
     public final native boolean optional() /*-{ return this.optional ? true : false; }-*/;
+    public final native boolean blocking() /*-{ return this.blocking ? true : false; }-*/;
     final native short _value()
     /*-{
       if (this.value) return this.value;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
index 7a477fa..0c0f529 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
@@ -17,9 +17,11 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
 import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.aria.client.Roles;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.Anchor;
 import com.google.gwt.user.client.ui.Widget;
 import com.google.gwtexpui.clippy.client.CopyableLabel;
@@ -115,6 +117,55 @@
       }
     }
 
+    public class CloneWithCommitMsgHookCommandLink extends DownloadCommandLink {
+      private final Project.NameKey project;
+
+      public CloneWithCommitMsgHookCommandLink(Project.NameKey project) {
+        super(DownloadCommand.CHECKOUT, "clone with commmit-msg hook");
+        this.project = project;
+      }
+
+      @Override
+      protected void setCurrentUrl(DownloadUrlLink link) {
+        widget.setVisible(true);
+
+        String sshPort = "29418";
+        String sshAddr = Gerrit.getConfig().getSshdAddress();
+        int p = sshAddr.lastIndexOf(':');
+        if (p != -1 && !sshAddr.endsWith(":")) {
+          sshPort = sshAddr.substring(p + 1);
+        }
+
+        StringBuilder cmd = new StringBuilder();
+        cmd.append("git clone ");
+        cmd.append(link.getUrlData());
+        cmd.append(" && scp -p -P ");
+        cmd.append(sshPort);
+        cmd.append(" ");
+        cmd.append(Gerrit.getUserAccount().getUserName());
+        cmd.append("@");
+
+        if (sshAddr.startsWith("*:") || p == -1) {
+          cmd.append(Window.Location.getHostName());
+        } else {
+          cmd.append(sshAddr.substring(0, p));
+        }
+
+        cmd.append(":hooks/commit-msg ");
+
+        p = project.get().lastIndexOf('/');
+        if (p != -1) {
+          cmd.append(project.get().substring(p + 1));
+        } else {
+          cmd.append(project.get());
+        }
+
+        cmd.append("/.git/hooks/");
+
+        copyLabel.setText(cmd.toString());
+      }
+    }
+
     public CopyableCommandLinkFactory(CopyableLabel label, Widget widget) {
       copyLabel = label;
       this.widget = widget;
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 fa2eb32..ad96f24 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
@@ -526,7 +526,8 @@
       new ErrorDialog(PatchUtil.C.intralineFailure()).show();
     } else if (intralineTimeout) {
       intralineTimeout = false;
-      new ErrorDialog(PatchUtil.C.intralineTimeout()).show();
+      new ErrorDialog(PatchUtil.C.intralineTimeout()).setText(
+          Gerrit.C.warnTitle()).show();
     }
     if (topView != null && prefs.get().isRetainHeader()) {
       setTopView(topView);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
index feee430..03d54e4 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.httpd;
 
 import com.google.common.cache.Cache;
+import com.google.common.collect.Lists;
 import com.google.gerrit.common.data.Capable;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.reviewdb.client.Project;
@@ -48,6 +49,8 @@
 import org.eclipse.jgit.http.server.resolver.AsIsFileService;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.PostReceiveHook;
+import org.eclipse.jgit.transport.PostReceiveHookChain;
 import org.eclipse.jgit.transport.ReceivePack;
 import org.eclipse.jgit.transport.UploadPack;
 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
@@ -247,13 +250,16 @@
     private final AsyncReceiveCommits.Factory factory;
     private final TransferConfig config;
     private DynamicSet<ReceivePackInitializer> receivePackInitializers;
+    private DynamicSet<PostReceiveHook> postReceiveHooks;
 
     @Inject
     ReceiveFactory(AsyncReceiveCommits.Factory factory, TransferConfig config,
-        DynamicSet<ReceivePackInitializer> receivePackInitializers) {
+        DynamicSet<ReceivePackInitializer> receivePackInitializers,
+        DynamicSet<PostReceiveHook> postReceiveHooks) {
       this.factory = factory;
       this.config = config;
       this.receivePackInitializers = receivePackInitializers;
+      this.postReceiveHooks = postReceiveHooks;
     }
 
     @Override
@@ -273,6 +279,8 @@
       rp.setTimeout(config.getTimeout());
       rp.setMaxObjectSizeLimit(config.getMaxObjectSizeLimit());
       init(pc.getProject().getNameKey(), rp);
+      rp.setPostReceiveHook(PostReceiveHookChain.newChain(
+          Lists.newArrayList(postReceiveHooks)));
       req.setAttribute(ATT_RC, rc);
       return rp;
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java
index 4faae5d..9d813fc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java
@@ -117,6 +117,7 @@
       lo.disliked = fromAcountInfo(li.disliked);
       lo.value = li.value;
       lo.optional = li.optional;
+      lo.blocking = li.blocking;
       lo.values = li.values;
       if (li.all != null) {
         lo.all = Lists.newArrayListWithExpectedSize(li.all.size());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 6d2dc58..ad6b804 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -456,6 +456,7 @@
                 break;
               case REJECT:
                 n.rejected = accountLoader.get(r.appliedBy);
+                n.blocking = true;
                 break;
               default:
                 break;
@@ -1002,6 +1003,7 @@
 
     public Short value;
     public Boolean optional;
+    public Boolean blocking;
 
     void addApproval(ApprovalInfo ai) {
       if (all == null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
index dd5101d..b581c67 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
@@ -104,6 +104,7 @@
   private boolean draft;
   private boolean runHooks;
   private boolean sendMail;
+  private Account.Id uploader;
 
   @Inject
   public PatchSetInserter(ChangeHooks hooks,
@@ -205,6 +206,11 @@
     return this;
   }
 
+  public PatchSetInserter setUploader(Account.Id uploader) {
+    this.uploader = uploader;
+    return this;
+  }
+
   public Change insert() throws InvalidChangeOperationException, OrmException,
       IOException {
     init();
@@ -321,6 +327,9 @@
       patchSet.setRevision(new RevId(commit.name()));
     }
     patchSet.setDraft(draft);
+    if (uploader != null) {
+      patchSet.setUploader(uploader);
+    }
   }
 
   private void validate() throws InvalidChangeOperationException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
index d9ec669..25c63b5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
@@ -395,7 +395,7 @@
         continue;
       }
 
-      PatchSetApproval c = current.remove(name);
+      PatchSetApproval c = current.remove(lt.getName());
       String normName = lt.getName();
       if (ent.getValue() == null || ent.getValue() == 0) {
         // User requested delete of this label.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
index b0fe0b5..8de6904 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
@@ -299,6 +299,7 @@
         .setCopyLabels(true)
         .setValidatePolicy(validate)
         .setDraft(originalPatchSet.isDraft())
+        .setUploader(uploader.getAccountId())
         .setSendMail(sendMail)
         .setRunHooks(runHooks);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index bd4b56f..c6598d4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -126,6 +126,7 @@
 import com.google.inject.internal.UniqueAnnotations;
 
 import org.apache.velocity.runtime.RuntimeInstance;
+import org.eclipse.jgit.transport.PostReceiveHook;
 
 import java.util.List;
 import java.util.Set;
@@ -245,6 +246,7 @@
     DynamicMap.mapOf(binder(), CapabilityDefinition.class);
     DynamicSet.setOf(binder(), GitReferenceUpdatedListener.class);
     DynamicSet.setOf(binder(), ReceivePackInitializer.class);
+    DynamicSet.setOf(binder(), PostReceiveHook.class);
     DynamicSet.setOf(binder(), NewProjectCreatedListener.class);
     DynamicSet.setOf(binder(), ProjectDeletedListener.class);
     DynamicSet.setOf(binder(), HeadUpdatedListener.class);
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 ac2bf9f..847eaee 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
@@ -954,7 +954,7 @@
     }
 
     RefControl ctl = projectControl.controlForRef(cmd.getRefName());
-    if (ctl.canCreate(rp.getRevWalk(), obj)) {
+    if (ctl.canCreate(rp.getRevWalk(), obj, allRefs.values().contains(obj))) {
       validateNewCommits(ctl, cmd);
       batch.addCommand(cmd);
     } else {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
index 1096a09..5424887 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
@@ -269,6 +269,9 @@
 
       for (final Map.Entry<Branch.NameKey, ObjectId> me : modules.entrySet()) {
         RevCommit c = myRw.parseCommit(me.getValue());
+        if (c == null) {
+          continue;
+        }
 
         msgbuf.append("\nProject: ");
         msgbuf.append(me.getKey().getParentKey().get());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
index 7a6ce7a..a97b3fd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
@@ -99,8 +99,9 @@
                 args.db, n.notes(), n.getPatchsetId())) {
               approvals.add(new PatchSetApproval(newPatchSet.getId(), a));
             }
-            args.db.patchSetApprovals().insert(approvals);
-
+            // rebaseChange.rebase() may already have copied some approvals,
+            // use upsert, not insert, to avoid constraint violation on database
+            args.db.patchSetApprovals().upsert(approvals);
             newMergeTip =
                 (CodeReviewCommit) args.rw.parseCommit(ObjectId
                     .fromString(newPatchSet.getRevision().get()));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
index 621809a..8e8c844 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
@@ -127,7 +127,7 @@
         }
       }
 
-      if (!refControl.canCreate(rw, object)) {
+      if (!refControl.canCreate(rw, object, true)) {
         throw new AuthException("Cannot create \"" + ref + "\"");
       }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
index a6ad374..858ff91 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
@@ -233,9 +233,10 @@
    *
    * @param rw revision pool {@code object} was parsed in.
    * @param object the object the user will start the reference with.
+   * @param existsOnServer the object exists on server or not.
    * @return {@code true} if the user specified can create a new Git ref
    */
-  public boolean canCreate(RevWalk rw, RevObject object) {
+  public boolean canCreate(RevWalk rw, RevObject object, boolean existsOnServer) {
     if (!canWrite()) {
       return false;
     }
@@ -253,8 +254,8 @@
     if (object instanceof RevCommit) {
       return getCurrentUser().getCapabilities().canAdministrateServer()
           || (owner && !isBlocked(Permission.CREATE))
-          || (canPerform(Permission.CREATE) && projectControl.canReadCommit(rw,
-              (RevCommit) object));
+          || (canPerform(Permission.CREATE) && (!existsOnServer && canUpdate() || projectControl
+              .canReadCommit(rw, (RevCommit) object)));
     } else if (object instanceof RevTag) {
       final RevTag tag = (RevTag) object;
       try {
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg b/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
index 12dcd52..d8f009b 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
@@ -26,7 +26,7 @@
 #
 add_ChangeId() {
 	clean_message=`sed -e '
-		/^diff --git a\/.*/{
+		/^diff --git .*/{
 			s///
 			q
 		}
@@ -81,7 +81,7 @@
 	# Skip the line starting with the diff command and everything after it,
 	# up to the end of the file, assuming it is only patch data.
 	# If more than one line before the diff was empty, strip all but one.
-	/^diff --git a/ {
+	/^diff --git / {
 		blankLines = 0
 		while (getline) { }
 		next
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
index 58f329f..a3c2cf5 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.sshd.commands;
 
+import com.google.common.collect.Lists;
 import com.google.gerrit.common.data.Capable;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.reviewdb.client.Account;
@@ -32,6 +33,8 @@
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefDatabase;
 import org.eclipse.jgit.transport.AdvertiseRefsHook;
+import org.eclipse.jgit.transport.PostReceiveHook;
+import org.eclipse.jgit.transport.PostReceiveHookChain;
 import org.eclipse.jgit.transport.ReceivePack;
 import org.kohsuke.args4j.Option;
 import org.slf4j.Logger;
@@ -64,6 +67,9 @@
   @Inject
   private DynamicSet<ReceivePackInitializer> receivePackInitializers;
 
+  @Inject
+  private DynamicSet<PostReceiveHook> postReceiveHooks;
+
   private final Set<Account.Id> reviewerId = new HashSet<Account.Id>();
   private final Set<Account.Id> ccId = new HashSet<Account.Id>();
 
@@ -103,6 +109,8 @@
     rp.setMaxObjectSizeLimit(config.getEffectiveMaxObjectSizeLimit(
         projectControl.getProjectState()));
     init(rp);
+    rp.setPostReceiveHook(PostReceiveHookChain.newChain(
+        Lists.newArrayList(postReceiveHooks)));
     try {
       rp.receive(in, out, err);
     } catch (UnpackException badStream) {
diff --git a/tools/default.defs b/tools/default.defs
index 0df8c1f..ff4b936 100644
--- a/tools/default.defs
+++ b/tools/default.defs
@@ -152,7 +152,8 @@
     mf_src = []
     mf_cmd += 'echo "Manifest-Version: 1.0" >$OUT;'
     mf_cmd += 'echo "Gerrit-ApiType: %s" >>$OUT;' % type
-    mf_cmd += 'echo "Implementation-Version: $v" >>$OUT'
+    mf_cmd += 'echo "Implementation-Version: $v" >>$OUT;'
+    mf_cmd += 'echo "Implementation-Vendor: Gerrit Code Review" >>$OUT'
     for line in manifest_entries:
       mf_cmd += ';echo "%s" >> $OUT' % line
   genrule(