Merge "Fix: 'Illegal label name'"
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/server/project/CustomLabelIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
index 83c9f38..f38ac89 100644
--- 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
@@ -21,6 +21,7 @@
 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;
@@ -77,8 +78,8 @@
     ChangeInfo c = get(r.getChangeId());
     LabelInfo q = c.labels.get(Q.getName());
     assertEquals(1, q.all.size());
-    assertNull(q.rejected);
-    assertNotNull(q.disliked);
+    assertNotNull(q.rejected);
+    assertNull(q.blocking);
   }
 
   @Test
@@ -90,8 +91,8 @@
     ChangeInfo c = get(r.getChangeId());
     LabelInfo q = c.labels.get(Q.getName());
     assertEquals(1, q.all.size());
-    assertNull(q.rejected);
-    assertNotNull(q.disliked);
+    assertNotNull(q.rejected);
+    assertNull(q.blocking);
   }
 
   @Test
@@ -103,8 +104,8 @@
     ChangeInfo c = get(r.getChangeId());
     LabelInfo q = c.labels.get(Q.getName());
     assertEquals(1, q.all.size());
-    assertNull(q.rejected);
-    assertNotNull(q.disliked);
+    assertNotNull(q.rejected);
+    assertNull(q.blocking);
   }
 
   @Test
@@ -118,6 +119,7 @@
     assertEquals(1, q.all.size());
     assertNull(q.disliked);
     assertNotNull(q.rejected);
+    assertTrue(q.blocking);
   }
 
   @Test
@@ -130,6 +132,7 @@
     assertEquals(1, q.all.size());
     assertNull(q.disliked);
     assertNotNull(q.rejected);
+    assertTrue(q.blocking);
   }
 
   private void saveLabelConfig() throws Exception {
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/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/diff/DiffTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java
index 6d09cec..8a64e76 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
@@ -39,6 +39,7 @@
   interface DiffTableStyle extends CssResource {
     String fullscreen();
     String intralineBg();
+    String dark();
     String diff();
     String noIntraline();
     String activeLine();
@@ -68,7 +69,8 @@
   private SideBySide2 parent;
   private boolean headerVisible;
 
-  DiffTable(SideBySide2 parent, PatchSet.Id base, PatchSet.Id revision, String path) {
+  DiffTable(SideBySide2 parent, PatchSet.Id base, PatchSet.Id revision,
+      String path) {
     patchSetSelectBoxA = new PatchSetSelectBox2(
         parent, DisplaySide.A, revision.getParentKey(), base, path);
     patchSetSelectBoxB = new PatchSetSelectBox2(
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
index 3c2ced9..09eacaa 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
@@ -79,6 +79,14 @@
     .noIntraline .a .intralineBg { background-color: #faa; }
     .noIntraline .b .intralineBg { background-color: #9f9; }
 
+    .dark .a .diff { background-color: #400; }
+    .dark .b .diff { background-color: #444; }
+
+    .dark .a .intralineBg { background-color: #888; }
+    .dark .b .intralineBg { background-color: #bbb; }
+    .dark .noIntraline .a .intralineBg { background-color: #400; }
+    .dark .noIntraline .b .intralineBg { background-color: #444; }
+
     .patchSetNav {
       background-color: #f7f7f7;
       line-height: 1;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
index b4ac7f2..ed7c3b6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
@@ -302,6 +302,7 @@
   @UiHandler("theme")
   void onTheme(ChangeEvent e) {
     prefs.theme(Theme.valueOf(theme.getValue(theme.getSelectedIndex())));
+    view.setThemeStyles(prefs.theme().isDark());
     view.operation(new Runnable() {
       @Override
       public void run() {
@@ -397,5 +398,14 @@
     theme.addItem(
         Theme.NEAT.name().toLowerCase(),
         Theme.NEAT.name());
+    theme.addItem(
+        Theme.MIDNIGHT.name().toLowerCase(),
+        Theme.MIDNIGHT.name());
+    theme.addItem(
+        Theme.NIGHT.name().toLowerCase(),
+        Theme.NIGHT.name());
+    theme.addItem(
+        Theme.TWILIGHT.name().toLowerCase(),
+        Theme.TWILIGHT.name());
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
index 78ec0ac..364d94c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
@@ -482,6 +482,7 @@
   }
 
   private void display(final CommentsCollections comments) {
+    setThemeStyles(prefs.theme().isDark());
     setShowTabs(prefs.showTabs());
     setShowIntraline(prefs.intralineDifference());
     if (prefs.showLineNumbers()) {
@@ -560,6 +561,14 @@
     return diff.intraline_status();
   }
 
+  void setThemeStyles(boolean d) {
+    if (d) {
+      diffTable.addStyleName(DiffTable.style.dark());
+    } else {
+      diffTable.removeStyleName(DiffTable.style.dark());
+    }
+  }
+
   void setShowTabs(boolean b) {
     if (b) {
       diffTable.addStyleName(DiffTable.style.showTabs());
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-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java
index 7d73574..a19ae08 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java
@@ -56,10 +56,26 @@
   }
 
   public static enum Theme {
+    // Light themes
     DEFAULT,
     ECLIPSE,
     ELEGANT,
     NEAT,
+    // Dark themes
+    MIDNIGHT,
+    NIGHT,
+    TWILIGHT;
+
+    public boolean isDark() {
+      switch (this) {
+        case MIDNIGHT:
+        case NIGHT:
+        case TWILIGHT:
+          return true;
+        default:
+          return false;
+      }
+    }
   }
 
   public static AccountDiffPreference createDefault(Account.Id accountId) {
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 cb852a8..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;
@@ -482,12 +483,18 @@
       return;
     }
 
-    if (score < 0) {
-      label.disliked = accountLoader.get(accountId);
-      label.value = score;
-    } else if (score > 0 && label.disliked == null) {
-      label.recommended = accountLoader.get(accountId);
-      label.value = score;
+    if (score != 0) {
+      if (score == type.getMin().getValue()) {
+        label.rejected = accountLoader.get(accountId);
+      } else if (score == type.getMax().getValue()) {
+        label.approved = accountLoader.get(accountId);
+      } else if (score < 0) {
+        label.disliked = accountLoader.get(accountId);
+        label.value = score;
+      } else if (score > 0 && label.disliked == null) {
+        label.recommended = accountLoader.get(accountId);
+        label.value = score;
+      }
     }
   }
 
@@ -996,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/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/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/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-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/lib/codemirror/cm3.defs b/lib/codemirror/cm3.defs
index fad0034..9679b1b 100644
--- a/lib/codemirror/cm3.defs
+++ b/lib/codemirror/cm3.defs
@@ -6,7 +6,10 @@
 CM3_THEMES = [
   'theme/eclipse.css',
   'theme/elegant.css',
+  'theme/midnight.css',
   'theme/neat.css',
+  'theme/night.css',
+  'theme/twilight.css',
 ]
 
 CM3_JS = [