Merge branch 'stable-3.7' into stable-3.8

* stable-3.7:
  PaginatingSource: Stop matching changes after desired limit is reached
  Fix typo in test method name
  Don't retry new change creation on lock failure
  pgm-init.txt: remove reference to Review DB from --batch option
  gr-change-view: Call reload event with clear patchset set when editing commit msg
  Don't fail metric computation due to duplicated metric names
  gr-file-list-header: Use change-model for fetching latest patchNum
  gr-reply-dialog: Use change-model for patchNum
  gr-change-actions: Use change-model for setting editBasedOnCurrentPatchSet and editPatchsetLoaded
  DefaultMemoryCacheFactoryTest: Fix flaky test
  Set uninteresting branches based on project configuration
  Split RebaseSorter.isAlreadyMerged() to avoid unnecessary work
  Fix creating changes in SubmoduleSubscriptionsWholeTopicMergeIT
  Update JGit to 5166ded098
  Update JGit to 0687c73a12
  Fix LDAP "Remember me" default value in login form
  Allow to hide download schemes from the REST API and  UI
  Update JGit to 176f17d05
  Update JGit to 596c445af
  Update JGit to 66b871b
  AndSource: Run isVisibleToPredicate based on its cost

Release-Notes: skip
Change-Id: I9048fb57672c41abc62c06e07bdc7e86225e3daa
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/java/com/google/gerrit/index/project/IndexedProjectQuery.java b/java/com/google/gerrit/index/project/IndexedProjectQuery.java
index 5fc74ca..52d08d6 100644
--- a/java/com/google/gerrit/index/project/IndexedProjectQuery.java
+++ b/java/com/google/gerrit/index/project/IndexedProjectQuery.java
@@ -14,11 +14,14 @@
 
 package com.google.gerrit.index.project;
 
+import static com.google.common.base.Preconditions.checkState;
+
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.index.Index;
 import com.google.gerrit.index.QueryOptions;
 import com.google.gerrit.index.query.DataSource;
 import com.google.gerrit.index.query.IndexedQuery;
+import com.google.gerrit.index.query.Matchable;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryParseException;
 
@@ -27,11 +30,27 @@
  * com.google.gerrit.index.IndexRewriter}. See {@link IndexedQuery}.
  */
 public class IndexedProjectQuery extends IndexedQuery<Project.NameKey, ProjectData>
-    implements DataSource<ProjectData> {
+    implements DataSource<ProjectData>, Matchable<ProjectData> {
 
   public IndexedProjectQuery(
       Index<Project.NameKey, ProjectData> index, Predicate<ProjectData> pred, QueryOptions opts)
       throws QueryParseException {
     super(index, pred, opts.convertForBackend());
   }
+
+  @Override
+  public boolean match(ProjectData object) {
+    Predicate<ProjectData> pred = getChild(0);
+    checkState(
+        pred.isMatchable(),
+        "match invoked, but child predicate %s doesn't implement %s",
+        pred,
+        Matchable.class.getName());
+    return pred.asMatchable().match(object);
+  }
+
+  @Override
+  public int getCost() {
+    return 1;
+  }
 }
diff --git a/java/com/google/gerrit/index/query/AndSource.java b/java/com/google/gerrit/index/query/AndSource.java
index f5f30bd..3adf881 100644
--- a/java/com/google/gerrit/index/query/AndSource.java
+++ b/java/com/google/gerrit/index/query/AndSource.java
@@ -16,7 +16,6 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 
-import com.google.common.collect.ImmutableList;
 import com.google.gerrit.index.IndexConfig;
 import java.util.Collection;
 import java.util.List;
@@ -24,36 +23,17 @@
 public class AndSource<T> extends AndPredicate<T> implements DataSource<T> {
   protected final DataSource<T> source;
 
-  private final IsVisibleToPredicate<T> isVisibleToPredicate;
   private final int start;
   private final int cardinality;
   private final IndexConfig indexConfig;
 
   public AndSource(Collection<? extends Predicate<T>> that, IndexConfig indexConfig) {
-    this(that, null, 0, indexConfig);
+    this(that, 0, indexConfig);
   }
 
-  public AndSource(
-      Predicate<T> that, IsVisibleToPredicate<T> isVisibleToPredicate, IndexConfig indexConfig) {
-    this(that, isVisibleToPredicate, 0, indexConfig);
-  }
-
-  public AndSource(
-      Predicate<T> that,
-      IsVisibleToPredicate<T> isVisibleToPredicate,
-      int start,
-      IndexConfig indexConfig) {
-    this(ImmutableList.of(that), isVisibleToPredicate, start, indexConfig);
-  }
-
-  public AndSource(
-      Collection<? extends Predicate<T>> that,
-      IsVisibleToPredicate<T> isVisibleToPredicate,
-      int start,
-      IndexConfig indexConfig) {
+  public AndSource(Collection<? extends Predicate<T>> that, int start, IndexConfig indexConfig) {
     super(that);
     checkArgument(start >= 0, "negative start: %s", start);
-    this.isVisibleToPredicate = isVisibleToPredicate;
     this.start = start;
     this.indexConfig = indexConfig;
 
@@ -93,16 +73,7 @@
   }
 
   @Override
-  public boolean isMatchable() {
-    return isVisibleToPredicate != null || super.isMatchable();
-  }
-
-  @Override
   public boolean match(T object) {
-    if (isVisibleToPredicate != null && !isVisibleToPredicate.match(object)) {
-      return false;
-    }
-
     if (super.isMatchable() && !super.match(object)) {
       return false;
     }
diff --git a/java/com/google/gerrit/index/query/PaginatingSource.java b/java/com/google/gerrit/index/query/PaginatingSource.java
index 337332f..8431ccc6 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/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 0e9f7ca..2baca53 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -1038,111 +1038,29 @@
           return;
         }
         try {
-          retryHelper
-              .changeUpdate(
-                  "insertChangesAndPatchSets",
-                  updateFactory -> {
-                    try (BatchUpdate bu =
-                            batchUpdateFactory.create(
-                                project.getNameKey(), user.materializedCopy(), TimeUtil.now());
-                        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);
         }
 
@@ -1166,6 +1084,90 @@
     }
   }
 
+  private void insertChangesAndPatchSets(
+      ReceiveCommand magicBranchCmd, List<CreateRequest> newChanges, Task replaceProgress)
+      throws RestApiException, IOException {
+    try (BatchUpdate bu =
+            batchUpdateFactory.create(
+                project.getNameKey(), user.materializedCopy(), TimeUtil.now());
+        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/index/group/IndexedGroupQuery.java b/java/com/google/gerrit/server/index/group/IndexedGroupQuery.java
index 7013e27..1d8cc1e 100644
--- a/java/com/google/gerrit/server/index/group/IndexedGroupQuery.java
+++ b/java/com/google/gerrit/server/index/group/IndexedGroupQuery.java
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.server.index.group;
 
+import static com.google.common.base.Preconditions.checkState;
+
 import com.google.gerrit.entities.AccountGroup;
 import com.google.gerrit.entities.InternalGroup;
 import com.google.gerrit.index.Index;
@@ -21,6 +23,7 @@
 import com.google.gerrit.index.QueryOptions;
 import com.google.gerrit.index.query.DataSource;
 import com.google.gerrit.index.query.IndexedQuery;
+import com.google.gerrit.index.query.Matchable;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryParseException;
 import java.util.HashSet;
@@ -31,7 +34,7 @@
  * com.google.gerrit.index.IndexRewriter}. See {@link IndexedQuery}.
  */
 public class IndexedGroupQuery extends IndexedQuery<AccountGroup.UUID, InternalGroup>
-    implements DataSource<InternalGroup> {
+    implements DataSource<InternalGroup>, Matchable<InternalGroup> {
 
   public static QueryOptions createOptions(
       IndexConfig config, int start, int pageSize, int limit, Set<String> fields) {
@@ -50,4 +53,20 @@
       throws QueryParseException {
     super(index, pred, opts.convertForBackend());
   }
+
+  @Override
+  public boolean match(InternalGroup object) {
+    Predicate<InternalGroup> pred = getChild(0);
+    checkState(
+        pred.isMatchable(),
+        "match invoked, but child predicate %s doesn't implement %s",
+        pred,
+        Matchable.class.getName());
+    return pred.asMatchable().match(object);
+  }
+
+  @Override
+  public int getCost() {
+    return 1;
+  }
 }
diff --git a/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java b/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java
index 9893d1a..eef913e 100644
--- a/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java
+++ b/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java
@@ -17,6 +17,7 @@
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.gerrit.server.query.account.AccountQueryBuilder.FIELD_LIMIT;
 
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.index.IndexConfig;
 import com.google.gerrit.index.query.AndSource;
 import com.google.gerrit.index.query.IndexPredicate;
@@ -78,7 +79,9 @@
   @Override
   protected Predicate<AccountState> enforceVisibility(Predicate<AccountState> pred) {
     return new AndSource<>(
-        pred, new AccountIsVisibleToPredicate(accountControlFactory.get()), start, indexConfig);
+        ImmutableList.of(pred, new AccountIsVisibleToPredicate(accountControlFactory.get())),
+        start,
+        indexConfig);
   }
 
   @Override
diff --git a/java/com/google/gerrit/server/query/change/AndChangeSource.java b/java/com/google/gerrit/server/query/change/AndChangeSource.java
index 98cada3..e4f768e 100644
--- a/java/com/google/gerrit/server/query/change/AndChangeSource.java
+++ b/java/com/google/gerrit/server/query/change/AndChangeSource.java
@@ -16,7 +16,6 @@
 
 import com.google.gerrit.index.IndexConfig;
 import com.google.gerrit.index.query.AndSource;
-import com.google.gerrit.index.query.IsVisibleToPredicate;
 import com.google.gerrit.index.query.Predicate;
 import java.util.Collection;
 import java.util.List;
@@ -28,11 +27,8 @@
   }
 
   public AndChangeSource(
-      Predicate<ChangeData> that,
-      IsVisibleToPredicate<ChangeData> isVisibleToPredicate,
-      int start,
-      IndexConfig indexConfig) {
-    super(that, isVisibleToPredicate, start, indexConfig);
+      Collection<Predicate<ChangeData>> that, int start, IndexConfig indexConfig) {
+    super(that, start, indexConfig);
   }
 
   @Override
diff --git a/java/com/google/gerrit/server/query/change/ChangeQueryProcessor.java b/java/com/google/gerrit/server/query/change/ChangeQueryProcessor.java
index 0f0535a..b7dc127 100644
--- a/java/com/google/gerrit/server/query/change/ChangeQueryProcessor.java
+++ b/java/com/google/gerrit/server/query/change/ChangeQueryProcessor.java
@@ -17,6 +17,7 @@
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.gerrit.server.query.change.ChangeQueryBuilder.FIELD_LIMIT;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableListMultimap;
 import com.google.gerrit.entities.Change;
 import com.google.gerrit.extensions.common.PluginDefinedInfo;
@@ -143,7 +144,9 @@
   @Override
   protected Predicate<ChangeData> enforceVisibility(Predicate<ChangeData> pred) {
     return new AndChangeSource(
-        pred, changeIsVisibleToPredicateFactory.forUser(userProvider.get()), start, indexConfig);
+        ImmutableList.of(pred, changeIsVisibleToPredicateFactory.forUser(userProvider.get())),
+        start,
+        indexConfig);
   }
 
   @Override
diff --git a/java/com/google/gerrit/server/query/group/GroupQueryProcessor.java b/java/com/google/gerrit/server/query/group/GroupQueryProcessor.java
index c6683fa..344a978 100644
--- a/java/com/google/gerrit/server/query/group/GroupQueryProcessor.java
+++ b/java/com/google/gerrit/server/query/group/GroupQueryProcessor.java
@@ -17,6 +17,7 @@
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.gerrit.server.query.group.GroupQueryBuilder.FIELD_LIMIT;
 
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.entities.InternalGroup;
 import com.google.gerrit.index.IndexConfig;
 import com.google.gerrit.index.query.AndSource;
@@ -80,8 +81,8 @@
   @Override
   protected Predicate<InternalGroup> enforceVisibility(Predicate<InternalGroup> pred) {
     return new AndSource<>(
-        pred,
-        new GroupIsVisibleToPredicate(groupControlFactory, userProvider.get()),
+        ImmutableList.of(
+            pred, new GroupIsVisibleToPredicate(groupControlFactory, userProvider.get())),
         start,
         indexConfig);
   }
diff --git a/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java b/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java
index 6dafa92..3877c25 100644
--- a/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java
+++ b/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java
@@ -17,6 +17,7 @@
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.gerrit.server.query.project.ProjectQueryBuilder.FIELD_LIMIT;
 
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.index.IndexConfig;
 import com.google.gerrit.index.project.ProjectData;
 import com.google.gerrit.index.project.ProjectIndexCollection;
@@ -82,8 +83,8 @@
   @Override
   protected Predicate<ProjectData> enforceVisibility(Predicate<ProjectData> pred) {
     return new AndSource<>(
-        pred,
-        new ProjectIsVisibleToPredicate(permissionBackend, userProvider.get()),
+        ImmutableList.of(
+            pred, new ProjectIsVisibleToPredicate(permissionBackend, userProvider.get())),
         start,
         indexConfig);
   }
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 bdda3fc5..c7b322e 100644
--- a/java/com/google/gerrit/server/submit/SubmitStrategy.java
+++ b/java/com/google/gerrit/server/submit/SubmitStrategy.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Sets;
 import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.BooleanProjectConfig;
 import com.google.gerrit.entities.BranchNameKey;
 import com.google.gerrit.entities.Change;
 import com.google.gerrit.entities.SubmissionId;
@@ -217,11 +218,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 ef2ca95..0d751f1 100644
--- a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
@@ -461,17 +461,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");
@@ -673,14 +675,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",
@@ -690,7 +694,8 @@
             "same-topic");
 
     // create a change for master branch in repo b
-    ObjectId bHead =
+    repoB.reset(revMasterBranchB);
+    ObjectId revMasterChangeB =
         pushChangeTo(
             repoB,
             "refs/for/master",
@@ -700,8 +705,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",
@@ -711,8 +716,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",
@@ -721,12 +726,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())
@@ -746,8 +751,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");
@@ -756,7 +762,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",
@@ -766,8 +773,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",
@@ -776,9 +783,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/server/account/externalids/ExternalIDCacheLoaderTest.java b/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java
index 8f2d613..0a874db 100644
--- a/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java
+++ b/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java
@@ -183,7 +183,7 @@
   public void handlesTreePrefixesInDifferentialReload() throws Exception {
     // Create more than 256 notes (NoteMap's current sharding limit) and check that we really have
     // created a situation where NoteNames are sharded.
-    ObjectId oldState = inserExternalIds(257);
+    ObjectId oldState = insertExternalIds(257);
     assertAllFilesHaveSlashesInPath();
     ObjectId head = insertExternalId(500, 500);
     externalIdCache.put(oldState, allFromGit(oldState));
@@ -196,7 +196,7 @@
   @Test
   public void handlesReshard() throws Exception {
     // Create 256 notes (NoteMap's current sharding limit) and check that we are not yet sharding
-    ObjectId oldState = inserExternalIds(256);
+    ObjectId oldState = insertExternalIds(256);
     assertNoFilesHaveSlashesInPath();
     // Create one more external ID and then have the Loader compute the new state
     ObjectId head = insertExternalId(500, 500);
@@ -223,7 +223,7 @@
     return AllExternalIds.create(externalIdReader.all(revision).stream());
   }
 
-  private ObjectId inserExternalIds(int numberOfIdsToInsert) throws Exception {
+  private ObjectId insertExternalIds(int numberOfIdsToInsert) throws Exception {
     ObjectId oldState = null;
     // Create more than 256 notes (NoteMap's current sharding limit) and check that we really have
     // created a situation where NoteNames are sharded.
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>