Merge "Bump JGit to 5ae8d28" into stable-3.5
diff --git a/Documentation/pgm-init.txt b/Documentation/pgm-init.txt
index 3c9e3fc..4b346fe 100644
--- a/Documentation/pgm-init.txt
+++ b/Documentation/pgm-init.txt
@@ -38,11 +38,6 @@
 	install, reasonable configuration defaults are chosen based
 	on the whims of the Gerrit developers. On upgrades, the existing
 	settings in `gerrit.config` are respected.
-+
-If during a schema migration unused objects (e.g. tables, columns)
-are detected, they are *not* automatically dropped; a list of SQL
-statements to drop these objects is provided. To drop the unused
-objects these SQL statements must be executed manually.
 
 --delete-caches::
 	Force deletion of all persistent cache files. Note that
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index 4056816..bab3ff0 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -2071,10 +2071,11 @@
 |`start_time` ||The start time of the task.
 |`delay`      ||The remaining delay of the task.
 |`command`    ||The command of the task.
+|`queue_name` ||The work queue the task is associated with.
 |`remote_name`|optional|
 The remote name. May only be set for tasks that are associated with a
 project.
-|`project`    |optional|The project the task is associated with.
+|`project_name`    |optional|The project the task is associated with.
 |====================================
 
 [[task-summary-info]]
diff --git a/java/com/google/gerrit/auth/BUILD b/java/com/google/gerrit/auth/BUILD
index e844696..f04334d 100644
--- a/java/com/google/gerrit/auth/BUILD
+++ b/java/com/google/gerrit/auth/BUILD
@@ -12,8 +12,6 @@
     srcs = glob(
         ["**/*.java"],
     ),
-    resource_strip_prefix = "resources",
-    resources = ["//resources/com/google/gerrit/server"],
     visibility = ["//visibility:public"],
     deps = [
         "//java/com/google/gerrit/common:annotations",
diff --git a/java/com/google/gerrit/index/query/PaginatingSource.java b/java/com/google/gerrit/index/query/PaginatingSource.java
index fd3a218..b05c8f4 100644
--- a/java/com/google/gerrit/index/query/PaginatingSource.java
+++ b/java/com/google/gerrit/index/query/PaginatingSource.java
@@ -87,6 +87,9 @@
                   r.add(data);
                 }
                 pageResultSize++;
+                if (r.size() > limit) {
+                  break;
+                }
               }
               nextStart += pageResultSize;
               searchAfter = next.searchAfter();
diff --git a/java/com/google/gerrit/metrics/dropwizard/BUILD b/java/com/google/gerrit/metrics/dropwizard/BUILD
index 4b3859f..dbb8f5e 100644
--- a/java/com/google/gerrit/metrics/dropwizard/BUILD
+++ b/java/com/google/gerrit/metrics/dropwizard/BUILD
@@ -12,6 +12,7 @@
         "//lib:args4j",
         "//lib:guava",
         "//lib/dropwizard:dropwizard-core",
+        "//lib/flogger:api",
         "//lib/guice",
     ],
 )
diff --git a/java/com/google/gerrit/metrics/dropwizard/BucketedCallback.java b/java/com/google/gerrit/metrics/dropwizard/BucketedCallback.java
index b3860f7..da9ec70 100644
--- a/java/com/google/gerrit/metrics/dropwizard/BucketedCallback.java
+++ b/java/com/google/gerrit/metrics/dropwizard/BucketedCallback.java
@@ -110,7 +110,7 @@
     }
   }
 
-  private String submetric(Object key) {
+  String submetric(Object key) {
     return DropWizardMetricMaker.name(ordering, name, name(key));
   }
 
diff --git a/java/com/google/gerrit/metrics/dropwizard/CallbackMetricImpl1.java b/java/com/google/gerrit/metrics/dropwizard/CallbackMetricImpl1.java
index d718035..bd3caf9 100644
--- a/java/com/google/gerrit/metrics/dropwizard/CallbackMetricImpl1.java
+++ b/java/com/google/gerrit/metrics/dropwizard/CallbackMetricImpl1.java
@@ -15,13 +15,17 @@
 package com.google.gerrit.metrics.dropwizard;
 
 import com.codahale.metrics.MetricRegistry;
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.metrics.CallbackMetric1;
 import com.google.gerrit.metrics.Description;
 import com.google.gerrit.metrics.Field;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 
 /** Optimized version of {@link BucketedCallback} for single dimension. */
 class CallbackMetricImpl1<F1, V> extends BucketedCallback<V> {
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
   CallbackMetricImpl1(
       DropWizardMetricMaker metrics,
       MetricRegistry registry,
@@ -44,9 +48,14 @@
 
     @Override
     public void set(F1 field1, V value) {
-      BucketedCallback<V>.ValueGauge cell = getOrCreate(field1);
-      cell.value = value;
-      cell.set = true;
+      try {
+        BucketedCallback<V>.ValueGauge cell = getOrCreate(field1);
+        cell.value = value;
+        cell.set = true;
+      } catch (IllegalArgumentException e) {
+        logger.atWarning().withCause(e).atMostEvery(1, TimeUnit.HOURS).log(
+            "Unable to register duplicate metric: %s", submetric(field1));
+      }
     }
 
     @Override
diff --git a/java/com/google/gerrit/server/audit/BUILD b/java/com/google/gerrit/server/audit/BUILD
index 3faa259..f19cb8b 100644
--- a/java/com/google/gerrit/server/audit/BUILD
+++ b/java/com/google/gerrit/server/audit/BUILD
@@ -5,8 +5,6 @@
     srcs = glob(
         ["**/*.java"],
     ),
-    resource_strip_prefix = "resources",
-    resources = ["//resources/com/google/gerrit/server"],
     visibility = ["//visibility:public"],
     deps = [
         "//java/com/google/gerrit/entities",
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 6be072a..951eb55 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -1019,111 +1019,29 @@
         return;
       }
       try {
-        retryHelper
-            .changeUpdate(
-                "insertChangesAndPatchSets",
-                updateFactory -> {
-                  try (BatchUpdate bu =
-                          updateFactory.create(
-                              project.getNameKey(), user.materializedCopy(), TimeUtil.nowTs());
-                      ObjectInserter ins = repo.newObjectInserter();
-                      ObjectReader reader = ins.newReader();
-                      RevWalk rw = new RevWalk(reader)) {
-                    bu.setRepository(repo, rw, ins);
-                    bu.setRefLogMessage("push");
-                    if (magicBranch != null) {
-                      bu.setNotify(magicBranch.getNotifyForNewChange());
-                    }
-
-                    logger.atFine().log("Adding %d replace requests", newChanges.size());
-                    for (ReplaceRequest replace : replaceByChange.values()) {
-                      replace.addOps(bu, replaceProgress);
-                      if (magicBranch != null) {
-                        bu.setNotifyHandling(
-                            replace.ontoChange, magicBranch.getNotifyHandling(replace.notes));
-                        if (magicBranch.shouldPublishComments()) {
-                          bu.addOp(
-                              replace.notes.getChangeId(),
-                              publishCommentsOp.create(replace.psId, project.getNameKey()));
-                          Optional<ChangeNotes> changeNotes =
-                              getChangeNotes(replace.notes.getChangeId());
-                          if (!changeNotes.isPresent()) {
-                            // If not present, no need to update attention set here since this is a
-                            // new change.
-                            continue;
-                          }
-                          List<HumanComment> drafts =
-                              commentsUtil.draftByChangeAuthor(
-                                  changeNotes.get(), user.getAccountId());
-                          if (drafts.isEmpty()) {
-                            // If no comments, attention set shouldn't update since the user didn't
-                            // reply.
-                            continue;
-                          }
-                          replyAttentionSetUpdates.processAutomaticAttentionSetRulesOnReply(
-                              bu,
-                              changeNotes.get(),
-                              isReadyForReview(changeNotes.get()),
-                              user,
-                              drafts);
-                        }
-                      }
-                    }
-
-                    logger.atFine().log("Adding %d create requests", newChanges.size());
-                    for (CreateRequest create : newChanges) {
-                      create.addOps(bu);
-                    }
-
-                    logger.atFine().log("Adding %d group update requests", newChanges.size());
-                    updateGroups.forEach(r -> r.addOps(bu));
-
-                    logger.atFine().log("Executing batch");
-                    try {
-                      bu.execute();
-                    } catch (UpdateException e) {
-                      throw asRestApiException(e);
-                    }
-
-                    replaceByChange.values().stream()
-                        .forEach(
-                            req ->
-                                result.addChange(
-                                    ReceiveCommitsResult.ChangeStatus.REPLACED, req.ontoChange));
-                    newChanges.stream()
-                        .forEach(
-                            req ->
-                                result.addChange(
-                                    ReceiveCommitsResult.ChangeStatus.CREATED, req.changeId));
-
-                    if (magicBranchCmd != null) {
-                      magicBranchCmd.setResult(OK);
-                    }
-                    for (ReplaceRequest replace : replaceByChange.values()) {
-                      String rejectMessage = replace.getRejectMessage();
-                      if (rejectMessage == null) {
-                        if (replace.inputCommand.getResult() == NOT_ATTEMPTED) {
-                          // Not necessarily the magic branch, so need to set OK on the original
-                          // value.
-                          replace.inputCommand.setResult(OK);
-                        }
-                      } else {
-                        logger.atFine().log("Rejecting due to message from ReplaceOp");
-                        reject(replace.inputCommand, rejectMessage);
-                      }
-                    }
-                  }
-                  return null;
-                })
-            .defaultTimeoutMultiplier(5)
-            .call();
+        if (!newChanges.isEmpty()) {
+          // TODO: Retry lock failures on new change insertions. The retry will
+          //  likely have to move to a higher layer to be able to achieve that
+          //  due to state that needs to be reset with each retry attempt.
+          insertChangesAndPatchSets(magicBranchCmd, newChanges, replaceProgress);
+        } else {
+          retryHelper
+              .changeUpdate(
+                  "insertPatchSets",
+                  updateFactory -> {
+                    insertChangesAndPatchSets(magicBranchCmd, newChanges, replaceProgress);
+                    return null;
+                  })
+              .defaultTimeoutMultiplier(5)
+              .call();
+        }
       } catch (ResourceConflictException e) {
         addError(e.getMessage());
         reject(magicBranchCmd, "conflict");
       } catch (BadRequestException | UnprocessableEntityException | AuthException e) {
         logger.atFine().withCause(e).log("Rejecting due to client error");
         reject(magicBranchCmd, e.getMessage());
-      } catch (RestApiException | UpdateException e) {
+      } catch (RestApiException | IOException | UpdateException e) {
         throw new StorageException("Can't insert change/patch set for " + project.getName(), e);
       }
 
@@ -1146,6 +1064,87 @@
     }
   }
 
+  private void insertChangesAndPatchSets(
+      ReceiveCommand magicBranchCmd, List<CreateRequest> newChanges, Task replaceProgress)
+      throws RestApiException, IOException {
+    try (BatchUpdate bu =
+            batchUpdateFactory.create(
+                project.getNameKey(), user.materializedCopy(), TimeUtil.nowTs());
+        ObjectInserter ins = repo.newObjectInserter();
+        ObjectReader reader = ins.newReader();
+        RevWalk rw = new RevWalk(reader)) {
+      bu.setRepository(repo, rw, ins);
+      bu.setRefLogMessage("push");
+      if (magicBranch != null) {
+        bu.setNotify(magicBranch.getNotifyForNewChange());
+      }
+
+      logger.atFine().log("Adding %d replace requests", newChanges.size());
+      for (ReplaceRequest replace : replaceByChange.values()) {
+        replace.addOps(bu, replaceProgress);
+        if (magicBranch != null) {
+          bu.setNotifyHandling(replace.ontoChange, magicBranch.getNotifyHandling(replace.notes));
+          if (magicBranch.shouldPublishComments()) {
+            bu.addOp(
+                replace.notes.getChangeId(),
+                publishCommentsOp.create(replace.psId, project.getNameKey()));
+            Optional<ChangeNotes> changeNotes = getChangeNotes(replace.notes.getChangeId());
+            if (!changeNotes.isPresent()) {
+              // If not present, no need to update attention set here since this is a new change.
+              continue;
+            }
+            List<HumanComment> drafts =
+                commentsUtil.draftByChangeAuthor(changeNotes.get(), user.getAccountId());
+            if (drafts.isEmpty()) {
+              // If no comments, attention set shouldn't update since the user didn't reply.
+              continue;
+            }
+            replyAttentionSetUpdates.processAutomaticAttentionSetRulesOnReply(
+                bu, changeNotes.get(), isReadyForReview(changeNotes.get()), user, drafts);
+          }
+        }
+      }
+
+      logger.atFine().log("Adding %d create requests", newChanges.size());
+      for (CreateRequest create : newChanges) {
+        create.addOps(bu);
+      }
+
+      logger.atFine().log("Adding %d group update requests", newChanges.size());
+      updateGroups.forEach(r -> r.addOps(bu));
+
+      logger.atFine().log("Executing batch");
+      try {
+        bu.execute();
+      } catch (UpdateException e) {
+        throw asRestApiException(e);
+      }
+
+      replaceByChange.values().stream()
+          .forEach(
+              req -> result.addChange(ReceiveCommitsResult.ChangeStatus.REPLACED, req.ontoChange));
+      newChanges.stream()
+          .forEach(
+              req -> result.addChange(ReceiveCommitsResult.ChangeStatus.CREATED, req.changeId));
+
+      if (magicBranchCmd != null) {
+        magicBranchCmd.setResult(OK);
+      }
+      for (ReplaceRequest replace : replaceByChange.values()) {
+        String rejectMessage = replace.getRejectMessage();
+        if (rejectMessage == null) {
+          if (replace.inputCommand.getResult() == NOT_ATTEMPTED) {
+            // Not necessarily the magic branch, so need to set OK on the original value.
+            replace.inputCommand.setResult(OK);
+          }
+        } else {
+          logger.atFine().log("Rejecting due to message from ReplaceOp");
+          reject(replace.inputCommand, rejectMessage);
+        }
+      }
+    }
+  }
+
   private boolean isReadyForReview(ChangeNotes changeNotes) {
     return (!changeNotes.getChange().isWorkInProgress() && !magicBranch.workInProgress)
         || magicBranch.ready;
diff --git a/java/com/google/gerrit/server/submit/RebaseSorter.java b/java/com/google/gerrit/server/submit/RebaseSorter.java
index 4775768..e960284 100644
--- a/java/com/google/gerrit/server/submit/RebaseSorter.java
+++ b/java/com/google/gerrit/server/submit/RebaseSorter.java
@@ -40,7 +40,7 @@
   private final CurrentUser caller;
   private final CodeReviewRevWalk rw;
   private final RevFlag canMergeFlag;
-  private final RevCommit initialTip;
+  private final Set<RevCommit> uninterestingBranchTips;
   private final Set<RevCommit> alreadyAccepted;
   private final Provider<InternalChangeQuery> queryProvider;
   private final Set<CodeReviewCommit> incoming;
@@ -48,7 +48,7 @@
   public RebaseSorter(
       CurrentUser caller,
       CodeReviewRevWalk rw,
-      RevCommit initialTip,
+      Set<RevCommit> uninterestingBranchTips,
       Set<RevCommit> alreadyAccepted,
       RevFlag canMergeFlag,
       Provider<InternalChangeQuery> queryProvider,
@@ -56,7 +56,7 @@
     this.caller = caller;
     this.rw = rw;
     this.canMergeFlag = canMergeFlag;
-    this.initialTip = initialTip;
+    this.uninterestingBranchTips = uninterestingBranchTips;
     this.alreadyAccepted = alreadyAccepted;
     this.queryProvider = queryProvider;
     this.incoming = incoming;
@@ -70,15 +70,16 @@
 
       rw.resetRetain(canMergeFlag);
       rw.markStart(n);
-      if (initialTip != null) {
-        rw.markUninteresting(initialTip);
+      for (RevCommit uninterestingBranchTip : uninterestingBranchTips) {
+        rw.markUninteresting(uninterestingBranchTip);
       }
 
       CodeReviewCommit c;
       final List<CodeReviewCommit> contents = new ArrayList<>();
       while ((c = rw.next()) != null) {
         if (!c.has(canMergeFlag) || !incoming.contains(c)) {
-          if (isAlreadyMerged(c, n.change().getDest())) {
+          if (isMergedInBranchAsSubmittedChange(c, n.change().getDest())
+              || isAlreadyMergedInAnyBranch(c)) {
             rw.markUninteresting(c);
           } else {
             // We cannot merge n as it would bring something we
@@ -108,7 +109,7 @@
     return sorted;
   }
 
-  private boolean isAlreadyMerged(CodeReviewCommit commit, BranchNameKey dest) throws IOException {
+  private boolean isAlreadyMergedInAnyBranch(CodeReviewCommit commit) throws IOException {
     try (CodeReviewRevWalk mirw = CodeReviewCommit.newRevWalk(rw.getObjectReader())) {
       mirw.reset();
       mirw.markStart(commit);
@@ -120,22 +121,24 @@
           return true;
         }
       }
-
-      // check if the commit associated change is merged in the same branch
-      List<ChangeData> changes = queryProvider.get().byCommit(commit);
-      for (ChangeData change : changes) {
-        if (change.change().isMerged() && change.change().getDest().equals(dest)) {
-          logger.atFine().log(
-              "Dependency %s associated with merged change %s.", commit.getName(), change.getId());
-          return true;
-        }
-      }
       return false;
     } catch (StorageException e) {
       throw new IOException(e);
     }
   }
 
+  private boolean isMergedInBranchAsSubmittedChange(CodeReviewCommit commit, BranchNameKey dest) {
+    List<ChangeData> changes = queryProvider.get().byBranchCommit(dest, commit.getId().getName());
+    for (ChangeData change : changes) {
+      if (change.change().isMerged()) {
+        logger.atFine().log(
+            "Dependency %s associated with merged change %s.", commit.getName(), change.getId());
+        return true;
+      }
+    }
+    return false;
+  }
+
   private static <T> T removeOne(Collection<T> c) {
     final Iterator<T> i = c.iterator();
     final T r = i.next();
diff --git a/java/com/google/gerrit/server/submit/SubmitStrategy.java b/java/com/google/gerrit/server/submit/SubmitStrategy.java
index 6291e6c..3b0ad00 100644
--- a/java/com/google/gerrit/server/submit/SubmitStrategy.java
+++ b/java/com/google/gerrit/server/submit/SubmitStrategy.java
@@ -20,6 +20,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Sets;
+import com.google.gerrit.entities.BooleanProjectConfig;
 import com.google.gerrit.entities.BranchNameKey;
 import com.google.gerrit.entities.Change;
 import com.google.gerrit.entities.SubmissionId;
@@ -212,11 +213,18 @@
           projectCache.get(destBranch.project()).orElseThrow(illegalState(destBranch.project()));
       this.mergeSorter =
           new MergeSorter(caller, rw, alreadyAccepted, canMergeFlag, queryProvider, incoming);
+      Set<RevCommit> uninterestingBranchTips;
+      if (project.is(BooleanProjectConfig.CREATE_NEW_CHANGE_FOR_ALL_NOT_IN_TARGET)) {
+        RevCommit initialTip = mergeTip.getInitialTip();
+        uninterestingBranchTips = initialTip == null ? Set.of() : Set.of(initialTip);
+      } else {
+        uninterestingBranchTips = alreadyAccepted;
+      }
       this.rebaseSorter =
           new RebaseSorter(
               caller,
               rw,
-              mergeTip.getInitialTip(),
+              uninterestingBranchTips,
               alreadyAccepted,
               canMergeFlag,
               queryProvider,
diff --git a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
index 8367f60..428d4f1 100644
--- a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
@@ -483,17 +483,19 @@
     allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
     allowMatchingSubmoduleSubscription(subKey, "refs/heads/dev", superKey, "refs/heads/master");
 
-    ObjectId devHead = pushChangeTo(subRepo, "dev");
+    ObjectId revMasterBranch = pushChangeTo(subRepo, "master");
+    ObjectId revDevBranch = pushChangeTo(subRepo, "dev");
     Config config = new Config();
     prepareSubmoduleConfigEntry(config, subKey, nameKey("sub-master"), "master");
     prepareSubmoduleConfigEntry(config, subKey, nameKey("sub-dev"), "dev");
     pushSubmoduleConfig(superRepo, "master", config);
 
+    subRepo.reset(revMasterBranch);
     ObjectId subMasterId =
         pushChangeTo(
             subRepo, "refs/for/master", "some message", "b.txt", "content b", "same-topic");
 
-    subRepo.reset(devHead);
+    subRepo.reset(revDevBranch);
     ObjectId subDevId =
         pushChangeTo(
             subRepo, "refs/for/dev", "some message in dev", "b.txt", "content b", "same-topic");
@@ -701,14 +703,16 @@
 
     TestRepository<?> repoA = cloneProject(keyA);
     TestRepository<?> repoB = cloneProject(keyB);
-    // bootstrap the dev branch
-    ObjectId a0 = pushChangeTo(repoA, "dev");
 
-    // bootstrap the dev branch
-    ObjectId b0 = pushChangeTo(repoB, "dev");
+    // Create master- and dev branches in both repositories
+    ObjectId revMasterBranchA = pushChangeTo(repoA, "master");
+    ObjectId revMasterBranchB = pushChangeTo(repoB, "master");
+    ObjectId revDevBranchA = pushChangeTo(repoA, "dev");
+    ObjectId revDevBranchB = pushChangeTo(repoB, "dev");
 
     // create a change for master branch in repo a
-    ObjectId aHead =
+    repoA.reset(revMasterBranchA);
+    ObjectId revMasterChangeA =
         pushChangeTo(
             repoA,
             "refs/for/master",
@@ -718,7 +722,8 @@
             "same-topic");
 
     // create a change for master branch in repo b
-    ObjectId bHead =
+    repoB.reset(revMasterBranchB);
+    ObjectId revMasterChangeB =
         pushChangeTo(
             repoB,
             "refs/for/master",
@@ -728,8 +733,8 @@
             "same-topic");
 
     // create a change for dev branch in repo a
-    repoA.reset(a0);
-    ObjectId aDevHead =
+    repoA.reset(revDevBranchA);
+    ObjectId revDevChangeA =
         pushChangeTo(
             repoA,
             "refs/for/dev",
@@ -739,8 +744,8 @@
             "same-topic");
 
     // create a change for dev branch in repo b
-    repoB.reset(b0);
-    ObjectId bDevHead =
+    repoB.reset(revDevBranchB);
+    ObjectId revDevChangeB =
         pushChangeTo(
             repoB,
             "refs/for/dev",
@@ -749,12 +754,12 @@
             "some message in b dev.txt",
             "same-topic");
 
-    approve(getChangeId(repoA, aHead).get());
-    approve(getChangeId(repoB, bHead).get());
-    approve(getChangeId(repoA, aDevHead).get());
-    approve(getChangeId(repoB, bDevHead).get());
+    approve(getChangeId(repoA, revMasterChangeA).get());
+    approve(getChangeId(repoB, revMasterChangeB).get());
+    approve(getChangeId(repoA, revDevChangeA).get());
+    approve(getChangeId(repoB, revDevChangeB).get());
 
-    gApi.changes().id(getChangeId(repoA, aDevHead).get()).current().submit();
+    gApi.changes().id(getChangeId(repoA, revDevChangeA).get()).current().submit();
     assertThat(projectOperations.project(keyA).getHead("refs/heads/master").getShortMessage())
         .contains("some message in a master.txt");
     assertThat(projectOperations.project(keyA).getHead("refs/heads/dev").getShortMessage())
@@ -774,8 +779,9 @@
     // bootstrap the dev branch
     pushChangeTo(repoA, "dev");
 
-    // bootstrap the dev branch
-    ObjectId b0 = pushChangeTo(repoB, "dev");
+    // Create master- and dev branches in repo b
+    ObjectId revMasterBranch = pushChangeTo(repoB, "master");
+    ObjectId revDevBranch = pushChangeTo(repoB, "dev");
 
     allowMatchingSubmoduleSubscription(keyB, "refs/heads/master", keyA, "refs/heads/master");
     allowMatchingSubmoduleSubscription(keyB, "refs/heads/dev", keyA, "refs/heads/dev");
@@ -784,7 +790,8 @@
     createSubmoduleSubscription(repoA, "dev", keyB, "dev");
 
     // create a change for master branch in repo b
-    ObjectId bHead =
+    repoB.reset(revMasterBranch);
+    ObjectId revMasterChange =
         pushChangeTo(
             repoB,
             "refs/for/master",
@@ -794,8 +801,8 @@
             "same-topic");
 
     // create a change for dev branch in repo b
-    repoB.reset(b0);
-    ObjectId bDevHead =
+    repoB.reset(revDevBranch);
+    ObjectId revDevChange =
         pushChangeTo(
             repoB,
             "refs/for/dev",
@@ -804,9 +811,9 @@
             "some message in b dev.txt",
             "same-topic");
 
-    approve(getChangeId(repoB, bHead).get());
-    approve(getChangeId(repoB, bDevHead).get());
-    gApi.changes().id(getChangeId(repoB, bHead).get()).current().submit();
+    approve(getChangeId(repoB, revMasterChange).get());
+    approve(getChangeId(repoB, revDevChange).get());
+    gApi.changes().id(getChangeId(repoB, revMasterChange).get()).current().submit();
 
     expectToHaveSubmoduleState(repoA, "master", keyB, repoB, "master");
     expectToHaveSubmoduleState(repoA, "dev", keyB, repoB, "dev");
diff --git a/javatests/com/google/gerrit/auth/BUILD b/javatests/com/google/gerrit/auth/BUILD
index 6a41d01..fa30f80a 100644
--- a/javatests/com/google/gerrit/auth/BUILD
+++ b/javatests/com/google/gerrit/auth/BUILD
@@ -7,8 +7,6 @@
     srcs = glob(
         ["**/*.java"],
     ),
-    resource_strip_prefix = "resources",
-    resources = ["//resources/com/google/gerrit/server"],
     tags = ["no_windows"],
     visibility = ["//visibility:public"],
     runtime_deps = [
diff --git a/javatests/com/google/gerrit/server/BUILD b/javatests/com/google/gerrit/server/BUILD
index 837e69d..efe21d7 100644
--- a/javatests/com/google/gerrit/server/BUILD
+++ b/javatests/com/google/gerrit/server/BUILD
@@ -25,8 +25,6 @@
         ["**/*.java"],
         exclude = CUSTOM_TRUTH_SUBJECTS,
     ),
-    resource_strip_prefix = "resources",
-    resources = ["//resources/com/google/gerrit/server"],
     tags = ["no_windows"],
     visibility = ["//visibility:public"],
     runtime_deps = [
diff --git a/javatests/com/google/gerrit/server/cache/mem/DefaultMemoryCacheFactoryTest.java b/javatests/com/google/gerrit/server/cache/mem/DefaultMemoryCacheFactoryTest.java
index da48341..7beb2ce 100644
--- a/javatests/com/google/gerrit/server/cache/mem/DefaultMemoryCacheFactoryTest.java
+++ b/javatests/com/google/gerrit/server/cache/mem/DefaultMemoryCacheFactoryTest.java
@@ -146,12 +146,11 @@
         cacheFactory.build(newCacheDef(1), newCacheLoader(identity()), CacheBackend.CAFFEINE);
 
     cache.put(TEST_CACHE_KEY, TEST_CACHE_VALUE);
-    cache.invalidate(TEST_CACHE_KEY);
 
     assertThat(forwardingRemovalListener.contains(TEST_CACHE_KEY, TEST_CACHE_VALUE)).isFalse();
+    cache.invalidate(TEST_CACHE_KEY);
 
     evictionReceived.await(TEST_TIMEOUT_SEC, TimeUnit.SECONDS);
-
     assertThat(forwardingRemovalListener.contains(TEST_CACHE_KEY, TEST_CACHE_VALUE)).isTrue();
     assertThat(forwardingRemovalListener.removalThreadName(TEST_CACHE_KEY))
         .startsWith(threadPoolPrefix);
diff --git a/javatests/com/google/gerrit/server/ioutil/BUILD b/javatests/com/google/gerrit/server/ioutil/BUILD
index ac9530f..8654522 100644
--- a/javatests/com/google/gerrit/server/ioutil/BUILD
+++ b/javatests/com/google/gerrit/server/ioutil/BUILD
@@ -6,7 +6,6 @@
     srcs = glob(
         ["**/*.java"],
     ),
-    resource_strip_prefix = "resources",
     visibility = ["//visibility:public"],
     deps = [
         "//java/com/google/gerrit/server/ioutil",
diff --git a/resources/com/google/gerrit/httpd/auth/ldap/LoginForm.html b/resources/com/google/gerrit/httpd/auth/ldap/LoginForm.html
index 593ea45..08c890d 100644
--- a/resources/com/google/gerrit/httpd/auth/ldap/LoginForm.html
+++ b/resources/com/google/gerrit/httpd/auth/ldap/LoginForm.html
@@ -43,6 +43,7 @@
             <input name="rememberme" id="f_remember"
                    type="checkbox"
                    value="1"
+                   checked="checked"
                    tabindex="3" />
             <label for="f_remember">Remember me</label>
           </td>