Merge "Buck: Upgrade to the latest version"
diff --git a/.gitignore b/.gitignore
index f2cb839..32a1826 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@
 /local.properties
 *.pyc
 /gwt-unitCache
+.DS_Store
 *.swp
 *.asc
 /bin/
diff --git a/Documentation/config-reverseproxy.txt b/Documentation/config-reverseproxy.txt
index c3dd12e..eff777b 100644
--- a/Documentation/config-reverseproxy.txt
+++ b/Documentation/config-reverseproxy.txt
@@ -99,7 +99,7 @@
 	  listen 80;
 	  server_name review.example.com;
 
-	  location /r/ {
+	  location ^~ /r/ {
 	    proxy_pass        http://127.0.0.1:8081;
 	    proxy_set_header  X-Forwarded-For $remote_addr;
 	    proxy_set_header  Host $host;
diff --git a/Documentation/pgm-init.txt b/Documentation/pgm-init.txt
index 39cd70d..6aa3a74 100644
--- a/Documentation/pgm-init.txt
+++ b/Documentation/pgm-init.txt
@@ -11,6 +11,7 @@
 	[--no-auto-start]
 	[--list-plugins]
 	[--install-plugin=<PLUGIN_NAME>]
+        [--dev]
 --
 
 == DESCRIPTION
@@ -51,6 +52,10 @@
 	This option may be supplied more than once to install multiple
 	plugins.
 
+--dev::
+	Install in developer mode. Default configuration settings are
+	chosen to run the Gerrit server as a developer.
+
 == CONTEXT
 This command can only be run on a server which has direct
 connectivity to the metadata database, and local access to the
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
index a9293f6..92d7980 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -35,11 +35,13 @@
 import com.google.gerrit.extensions.api.changes.AddReviewerInput;
 import com.google.gerrit.extensions.api.changes.RebaseInput;
 import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.RevisionApi;
 import com.google.gerrit.extensions.client.ChangeStatus;
 import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.common.ApprovalInfo;
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.common.ChangeMessageInfo;
+import com.google.gerrit.extensions.common.GitPerson;
 import com.google.gerrit.extensions.common.LabelInfo;
 import com.google.gerrit.extensions.common.RevisionInfo;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -171,9 +173,42 @@
         .revert();
   }
 
-  // Change is already up to date
-  @Test(expected = ResourceConflictException.class)
+  @Test
   public void rebase() throws Exception {
+    // Create two changes both with the same parent
+    PushOneCommit.Result r = createChange();
+    testRepo.reset("HEAD~1");
+    PushOneCommit.Result r2 = createChange();
+
+    // Approve and submit the first change
+    RevisionApi revision = gApi.changes()
+        .id(r.getChangeId())
+        .current();
+    revision.review(ReviewInput.approve());
+    revision.submit();
+
+    // Rebase the second change
+    gApi.changes()
+        .id(r2.getChangeId())
+        .current()
+        .rebase();
+
+    // Second change should have 2 patch sets
+    assertThat(r2.getPatchSetId().get()).isEqualTo(2);
+
+    // ...and the committer should be correct
+    ChangeInfo info = gApi.changes()
+        .id(r2.getChangeId()).get(EnumSet.of(
+            ListChangesOption.CURRENT_REVISION,
+            ListChangesOption.CURRENT_COMMIT));
+    GitPerson committer = info.revisions.get(
+        info.currentRevision).commit.committer;
+    assertThat(committer.name).isEqualTo(admin.fullName);
+    assertThat(committer.email).isEqualTo(admin.email);
+  }
+
+  @Test(expected = ResourceConflictException.class)
+  public void rebaseUpToDateChange() throws Exception {
     PushOneCommit.Result r = createChange();
     gApi.changes()
         .id(r.getChangeId())
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
index 2e991d9..16e7e61 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
@@ -21,9 +21,20 @@
 
 /** Data sent as part of the host page, to bootstrap the UI. */
 public class HostPageData {
+  /**
+   * Name of the cookie in which the XSRF token is sent from the server to the
+   * client during host page bootstrapping.
+   */
+  public static final String XSRF_COOKIE_NAME = "XSRF_TOKEN";
+
+  /**
+   * Name of the HTTP header in which the client must send the XSRF token to the
+   * server on each request.
+   */
+  public static final String XSRF_HEADER_NAME = "X-Gerrit-Auth";
+
   public String version;
   public DiffPreferencesInfo accountDiffPref;
-  public String xGerritAuth;
   public Theme theme;
   public List<String> plugins;
   public List<Message> messages;
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 ee67116..30e85ae 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
@@ -17,6 +17,7 @@
 import static com.google.gerrit.common.data.GlobalCapability.CREATE_GROUP;
 import static com.google.gerrit.common.data.GlobalCapability.CREATE_PROJECT;
 import static com.google.gerrit.common.data.GlobalCapability.VIEW_PLUGINS;
+import static com.google.gerrit.common.data.HostPageData.XSRF_COOKIE_NAME;
 
 import com.google.gerrit.client.account.AccountApi;
 import com.google.gerrit.client.account.AccountCapabilities;
@@ -477,8 +478,7 @@
         if (result.accountDiffPref != null) {
           myAccountDiffPref = result.accountDiffPref;
         }
-        if (result.xGerritAuth != null) {
-          xGerritAuth = result.xGerritAuth;
+        if (result.accountDiffPref != null) {
           // TODO: Support options on the GetDetail REST endpoint so that it can
           // also return the preferences. Then we can fetch everything with a
           // single request and we don't need the callback group anymore.
@@ -513,6 +513,8 @@
           editPrefs = null;
           onModuleLoad2(result);
         }
+        xGerritAuth = Cookies.getCookie(XSRF_COOKIE_NAME);
+        Cookies.removeCookie(XSRF_COOKIE_NAME);
       }
     }));
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
index 07d45e9..9a8e90c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
@@ -15,12 +15,15 @@
 package com.google.gerrit.client.account;
 
 import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.extensions.client.Theme;
 import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
+import com.google.gerrit.extensions.client.Theme;
 import com.google.gwt.core.client.JavaScriptObject;
 
 public class DiffPreferences extends JavaScriptObject {
   public static DiffPreferences create(DiffPreferencesInfo in) {
+    if (in == null) {
+      in = DiffPreferencesInfo.defaults();
+    }
     DiffPreferences p = createObject().cast();
     p.ignoreWhitespace(in.ignoreWhitespace);
     p.tabSize(in.tabSize);
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 a50768d..455a643 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
@@ -503,7 +503,7 @@
     AccountApi.putDiffPreferences(prefs, new GerritCallback<DiffPreferences>() {
       @Override
       public void onSuccess(DiffPreferences result) {
-        DiffPreferencesInfo p = Gerrit.getDiffPreferences();
+        DiffPreferencesInfo p = new DiffPreferencesInfo();
         result.copyTo(p);
         Gerrit.setDiffPreferences(p);
       }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
index 7fc84f0..eb902ad 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.client.diff;
 
 import static com.google.gerrit.extensions.client.DiffPreferencesInfo.WHOLE_FILE_CONTEXT;
-
 import static java.lang.Double.POSITIVE_INFINITY;
 
 import com.google.gerrit.client.Dispatcher;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
index 771423e..a0e25ad 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
@@ -21,6 +21,7 @@
 
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.RpcStatus;
+import com.google.gerrit.common.data.HostPageData;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.core.client.Scheduler;
@@ -449,7 +450,7 @@
     }
     req.setHeader("Accept", JSON_TYPE);
     if (Gerrit.getXGerritAuth() != null) {
-      req.setHeader("X-Gerrit-Auth", Gerrit.getXGerritAuth());
+      req.setHeader(HostPageData.XSRF_HEADER_NAME, Gerrit.getXGerritAuth());
     }
     return req;
   }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java
index a6e4b44..a1cfec7 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java
@@ -16,6 +16,7 @@
 
 import static java.util.concurrent.TimeUnit.HOURS;
 
+import com.google.gerrit.common.data.HostPageData;
 import com.google.gerrit.httpd.WebSessionManager.Key;
 import com.google.gerrit.httpd.WebSessionManager.Val;
 import com.google.gerrit.reviewdb.client.Account;
@@ -80,7 +81,7 @@
           val = manager.createVal(key, val);
         }
 
-        String token = request.getHeader("X-Gerrit-Auth");
+        String token = request.getHeader(HostPageData.XSRF_HEADER_NAME);
         if (val != null && token != null && token.equals(val.getAuth())) {
           okPaths.add(AccessPath.REST_API);
         }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
index 389dcc7..e21f973 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
@@ -68,6 +68,7 @@
 
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -78,6 +79,7 @@
 public class HostPageServlet extends HttpServlet {
   private static final Logger log =
       LoggerFactory.getLogger(HostPageServlet.class);
+
   private static final String HPD_ID = "gerrit_hostpagedata";
   private static final int DEFAULT_JS_LOAD_TIMEOUT = 5000;
 
@@ -124,7 +126,7 @@
     pluginsLoadTimeout = getPluginsLoadTimeout(cfg);
     getDiff = diffPref;
 
-    final String pageName = "HostPage.html";
+    String pageName = "HostPage.html";
     template = HtmlDomUtil.parseFile(getClass(), pageName);
     if (template == null) {
       throw new FileNotFoundException("No " + pageName + " in webapp");
@@ -141,7 +143,7 @@
     try (InputStream in = servletContext.getResourceAsStream("/" + src)) {
       if (in != null) {
         Hasher md = Hashing.md5().newHasher();
-        final byte[] buf = new byte[1024];
+        byte[] buf = new byte[1024];
         int n;
         while ((n = in.read(buf)) > 0) {
           md.putBytes(buf, 0, n);
@@ -158,7 +160,7 @@
     page = new Page();
   }
 
-  private static int getPluginsLoadTimeout(final Config cfg) {
+  private static int getPluginsLoadTimeout(Config cfg) {
     long cfgValue =
         ConfigUtil.getTimeUnit(cfg, "plugins", null, "jsLoadTimeout",
             DEFAULT_JS_LOAD_TIMEOUT, TimeUnit.MILLISECONDS);
@@ -168,7 +170,7 @@
     return (int) cfgValue;
   }
 
-  private void json(final Object data, final StringWriter w) {
+  private void json(Object data, StringWriter w) {
     JsonServlet.defaultGsonBuilder().create().toJson(data, w);
   }
 
@@ -186,16 +188,13 @@
   }
 
   @Override
-  protected void doGet(final HttpServletRequest req,
-      final HttpServletResponse rsp) throws IOException {
-    final Page.Content page = select(req);
-    final StringWriter w = new StringWriter();
-    final CurrentUser user = currentUser.get();
+  protected void doGet(HttpServletRequest req,
+      HttpServletResponse rsp) throws IOException {
+    Page.Content page = select(req);
+    StringWriter w = new StringWriter();
+    CurrentUser user = currentUser.get();
     if (user.isIdentifiedUser()) {
-      w.write(HPD_ID + ".xGerritAuth=");
-      json(session.get().getXGerritAuth(), w);
-      w.write(";");
-
+      setXGerritAuthCookie(req, rsp, session.get());
       w.write(HPD_ID + ".accountDiffPref=");
       json(getDiffPreferences(user.asIdentifiedUser()), w);
       w.write(";");
@@ -204,6 +203,7 @@
       json(signedInTheme, w);
       w.write(";");
     } else {
+      setXGerritAuthCookie(req, rsp, null);
       w.write(HPD_ID + ".theme=");
       json(signedOutTheme, w);
       w.write(";");
@@ -211,9 +211,9 @@
     plugins(w);
     messages(w);
 
-    final byte[] hpd = w.toString().getBytes(UTF_8);
-    final byte[] raw = Bytes.concat(page.part1, hpd, page.part2);
-    final byte[] tosend;
+    byte[] hpd = w.toString().getBytes(UTF_8);
+    byte[] raw = Bytes.concat(page.part1, hpd, page.part2);
+    byte[] tosend;
     if (RPCServletUtils.acceptsGzipEncoding(req)) {
       rsp.setHeader("Content-Encoding", "gzip");
       tosend = HtmlDomUtil.compress(raw);
@@ -230,6 +230,23 @@
     }
   }
 
+  private static void setXGerritAuthCookie(HttpServletRequest req,
+      HttpServletResponse rsp, WebSession session) {
+    String v = session != null ? session.getXGerritAuth() : "";
+    Cookie c = new Cookie(HostPageData.XSRF_COOKIE_NAME, v);
+    c.setPath("/");
+    c.setHttpOnly(false);
+    c.setSecure(isSecure(req));
+    c.setMaxAge(session != null
+        ? -1 // Set the cookie for this browser session.
+        : 0); // Remove the cookie (expire immediately).
+    rsp.addCookie(c);
+  }
+
+  private static boolean isSecure(HttpServletRequest req) {
+    return req.isSecure() || "https".equals(req.getScheme());
+  }
+
   private DiffPreferencesInfo getDiffPreferences(IdentifiedUser user) {
     try {
       return getDiff.apply(new AccountResource(user));
@@ -329,17 +346,17 @@
       header = injectXmlFile(hostDoc, "gerrit_header", site.site_header);
       footer = injectXmlFile(hostDoc, "gerrit_footer", site.site_footer);
 
-      final HostPageData pageData = new HostPageData();
+      HostPageData pageData = new HostPageData();
       pageData.version = Version.getVersion();
       pageData.isNoteDbEnabled = isNoteDbEnabled;
       pageData.pluginsLoadTimeout = pluginsLoadTimeout;
 
-      final StringWriter w = new StringWriter();
+      StringWriter w = new StringWriter();
       w.write("var " + HPD_ID + "=");
       json(pageData, w);
       w.write(";");
 
-      final Element data = HtmlDomUtil.find(hostDoc, HPD_ID);
+      Element data = HtmlDomUtil.find(hostDoc, HPD_ID);
       asScript(data);
       data.appendChild(hostDoc.createTextNode(w.toString()));
       data.appendChild(hostDoc.createComment(HPD_ID));
@@ -358,7 +375,7 @@
       return css.isStale() || header.isStale() || footer.isStale();
     }
 
-    private void asScript(final Element scriptNode) {
+    private void asScript(Element scriptNode) {
       scriptNode.setAttribute("type", "text/javascript");
       scriptNode.setAttribute("language", "javascript");
     }
@@ -368,8 +385,8 @@
       final byte[] part2;
 
       Content(Document hostDoc) throws IOException {
-        final String raw = HtmlDomUtil.toString(hostDoc);
-        final int p = raw.indexOf("<!--" + HPD_ID);
+        String raw = HtmlDomUtil.toString(hostDoc);
+        int p = raw.indexOf("<!--" + HPD_ID);
         if (p < 0) {
           throw new IOException("No tag in transformed host page HTML");
         }
@@ -380,8 +397,8 @@
 
     private FileInfo injectCssFile(Document hostDoc, String id, Path src)
         throws IOException {
-      final FileInfo info = new FileInfo(src);
-      final Element banner = HtmlDomUtil.find(hostDoc, id);
+      FileInfo info = new FileInfo(src);
+      Element banner = HtmlDomUtil.find(hostDoc, id);
       if (banner == null) {
         return info;
       }
@@ -402,8 +419,8 @@
 
     private FileInfo injectXmlFile(Document hostDoc, String id, Path src)
         throws IOException {
-      final FileInfo info = new FileInfo(src);
-      final Element banner = HtmlDomUtil.find(hostDoc, id);
+      FileInfo info = new FileInfo(src);
+      Element banner = HtmlDomUtil.find(hostDoc, id);
       if (banner == null) {
         return info;
       }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
index a77bcfa..e08b7ac 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
@@ -63,6 +63,10 @@
       usage = "Path to jar providing SecureStore implementation class")
   private String secureStoreLib;
 
+  @Option(name = "--dev",
+      usage = "Setup site with default options suitable for developers")
+  private boolean dev;
+
   @Inject
   Browser browser;
 
@@ -138,6 +142,11 @@
   }
 
   @Override
+  protected boolean isDev() {
+    return dev;
+  }
+
+  @Override
   protected String getSecureStoreLib() {
     return secureStoreLib;
   }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
index cd1c7a3..b200ed5 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
@@ -115,6 +115,7 @@
     }
 
     init.flags.autoStart = getAutoStart() && init.site.isNew;
+    init.flags.dev = isDev() && init.site.isNew;
     init.flags.skipPlugins = skipPlugins();
 
     final SiteRun run;
@@ -446,4 +447,8 @@
       System.err.println(msg + path);
     }
   }
+
+  protected boolean isDev() {
+    return false;
+  }
 }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAuth.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAuth.java
index 69f2c15..6b30f80 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAuth.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAuth.java
@@ -25,27 +25,25 @@
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
-import org.eclipse.jgit.lib.Config;
-
 /** Initialize the {@code auth} configuration section. */
 @Singleton
 class InitAuth implements InitStep {
   private static final String RECEIVE = "receive";
   private static final String ENABLE_SIGNED_PUSH = "enableSignedPush";
 
-  private final Config cfg;
   private final ConsoleUI ui;
   private final Section auth;
   private final Section ldap;
   private final Section receive;
   private final Libraries libraries;
+  private final InitFlags flags;
 
   @Inject
   InitAuth(InitFlags flags,
       ConsoleUI ui,
       Libraries libraries,
       Section.Factory sections) {
-    this.cfg = flags.cfg;
+    this.flags = flags;
     this.ui = ui;
     this.auth = sections.get("auth", null);
     this.ldap = sections.get("ldap", null);
@@ -66,8 +64,8 @@
   }
 
   private void initAuthType() {
-    AuthType authType =
-        auth.select("Authentication method", "type", AuthType.OPENID);
+    AuthType authType = auth.select("Authentication method", "type",
+        flags.dev ? AuthType.DEVELOPMENT_BECOME_ANY_ACCOUNT : AuthType.OPENID);
     switch (authType) {
       case HTTP:
       case HTTP_LDAP: {
@@ -129,7 +127,7 @@
   }
 
   private void initSignedPush() {
-    boolean def = cfg.getBoolean(RECEIVE, ENABLE_SIGNED_PUSH, false);
+    boolean def = flags.cfg.getBoolean(RECEIVE, ENABLE_SIGNED_PUSH, false);
     boolean enable = ui.yesno(def, "Enable signed push support");
     receive.set("enableSignedPush", Boolean.toString(enable));
     if (enable) {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java
index c8f03cc..bdd8b86 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java
@@ -39,6 +39,9 @@
   /** Skip plugins */
   public boolean skipPlugins;
 
+  /** Dev mode */
+  public boolean dev;
+
   public final FileBasedConfig cfg;
   public final SecureStore sec;
   public final List<String> installPlugins;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishDraftPatchSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishDraftPatchSet.java
index 6820115..9f2a3f9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishDraftPatchSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishDraftPatchSet.java
@@ -209,6 +209,11 @@
         throw new ResourceConflictException("Patch set is not a draft");
       }
       patchSet.setDraft(false);
+      // Force ETag invalidation if not done already
+      if (!wasDraftChange) {
+        ChangeUtil.updated(change);
+        ctx.getDb().changes().update(Collections.singleton(change));
+      }
       ctx.getDb().patchSets().update(Collections.singleton(patchSet));
     }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseChangeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseChangeOp.java
index 4130273..31bfc50 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseChangeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseChangeOp.java
@@ -199,7 +199,7 @@
       cb.setCommitter(committerIdent);
     } else {
       cb.setCommitter(ctx.getUser().asIdentifiedUser()
-          .newRefLogIdent(ctx.getWhen(), ctx.getTimeZone()));
+          .newCommitterIdent(ctx.getWhen(), ctx.getTimeZone()));
     }
     ObjectId objectId = ctx.getInserter().insert(cb);
     ctx.getInserter().flush();
diff --git a/lib/codemirror/BUCK b/lib/codemirror/BUCK
index 9756f5d..6187b3b 100644
--- a/lib/codemirror/BUCK
+++ b/lib/codemirror/BUCK
@@ -3,8 +3,8 @@
 include_defs('//lib/codemirror/closure.defs')
 
 REPO = MAVEN_CENTRAL
-VERSION = '5.7'
-SHA1 = '839a48a6c8d6b36193832a822911198ccba96bfe'
+VERSION = '5.8'
+SHA1 = '1cbe267adf1da9659dae49253305649dae2391e9'
 
 if REPO == MAVEN_CENTRAL:
   URL = REPO + 'org/webjars/codemirror/%s/codemirror-%s.jar' % (VERSION, VERSION)