Merge "Revert "Remove extension to override has:edit predicate""
diff --git a/java/com/google/gerrit/server/restapi/change/CherryPickChange.java b/java/com/google/gerrit/server/restapi/change/CherryPickChange.java
index 8b99e1c..677279e 100644
--- a/java/com/google/gerrit/server/restapi/change/CherryPickChange.java
+++ b/java/com/google/gerrit/server/restapi/change/CherryPickChange.java
@@ -175,7 +175,8 @@
         null,
         null,
         null,
-        null);
+        null,
+        Optional.empty());
   }
 
   /**
@@ -206,7 +207,17 @@
       throws IOException, InvalidChangeOperationException, UpdateException, RestApiException,
           ConfigInvalidException, NoSuchProjectException {
     return cherryPick(
-        sourceChange, project, sourceCommit, input, dest, TimeUtil.now(), null, null, null, null);
+        sourceChange,
+        project,
+        sourceCommit,
+        input,
+        dest,
+        TimeUtil.now(),
+        null,
+        null,
+        null,
+        null,
+        Optional.empty());
   }
 
   /**
@@ -228,6 +239,9 @@
    * @param idForNewChange The ID that the new change of the cherry pick will have. If provided and
    *     the cherry-pick doesn't result in creating a new change, then
    *     InvalidChangeOperationException is thrown.
+   * @param verifiedBaseCommit - base commit for the cherry-pick, which is guaranteed to be
+   *     associated with exactly one change and belong to a {@code dest} branch. This is currently
+   *     only used when this base commit was created in the same API call.
    * @return Result object that describes the cherry pick.
    * @throws IOException Unable to open repository or read from the database.
    * @throws InvalidChangeOperationException Parent or branch don't exist, or two changes with same
@@ -248,7 +262,8 @@
       @Nullable Change.Id revertedChange,
       @Nullable ObjectId changeIdForNewChange,
       @Nullable Change.Id idForNewChange,
-      @Nullable Boolean workInProgress)
+      @Nullable Boolean workInProgress,
+      Optional<RevCommit> verifiedBaseCommit)
       throws IOException, InvalidChangeOperationException, UpdateException, RestApiException,
           ConfigInvalidException, NoSuchProjectException {
     IdentifiedUser identifiedUser = user.get();
@@ -266,8 +281,9 @@
       }
 
       RevCommit baseCommit =
-          CommitUtil.getBaseCommit(
-              project.get(), queryProvider.get(), revWalk, destRef, input.base);
+          verifiedBaseCommit.orElse(
+              CommitUtil.getBaseCommit(
+                  project.get(), queryProvider.get(), revWalk, destRef, input.base));
 
       CodeReviewCommit commitToCherryPick = revWalk.parseCommit(sourceCommit);
 
diff --git a/java/com/google/gerrit/server/restapi/change/RevertSubmission.java b/java/com/google/gerrit/server/restapi/change/RevertSubmission.java
index 691fc75..3851e82 100644
--- a/java/com/google/gerrit/server/restapi/change/RevertSubmission.java
+++ b/java/com/google/gerrit/server/restapi/change/RevertSubmission.java
@@ -86,6 +86,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.Optional;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -310,6 +311,13 @@
     cherryPickInput.message = revertInput.message;
     ObjectId generatedChangeId = CommitMessageUtil.generateChangeId();
     Change.Id cherryPickRevertChangeId = Change.id(seq.nextChangeId());
+    RevCommit baseCommit = null;
+    if (cherryPickInput.base != null) {
+      try (Repository git = repoManager.openRepository(changeNotes.getProjectName());
+          RevWalk revWalk = new RevWalk(git.newObjectReader())) {
+        baseCommit = revWalk.parseCommit(ObjectId.fromString(cherryPickInput.base));
+      }
+    }
     try (RefUpdateContext ctx = RefUpdateContext.open(CHANGE_MODIFICATION)) {
       try (BatchUpdate bu = updateFactory.create(project, user.get(), TimeUtil.now())) {
         bu.setNotify(
@@ -323,7 +331,8 @@
                 generatedChangeId,
                 cherryPickRevertChangeId,
                 timestamp,
-                revertInput.workInProgress));
+                revertInput.workInProgress,
+                baseCommit));
         if (!revertInput.workInProgress) {
           commitUtil.addChangeRevertedNotificationOps(
               bu, changeNotes.getChangeId(), cherryPickRevertChangeId, generatedChangeId.name());
@@ -548,18 +557,21 @@
     private final Change.Id cherryPickRevertChangeId;
     private final Instant timestamp;
     private final boolean workInProgress;
+    private final RevCommit baseCommit;
 
     CreateCherryPickOp(
         ObjectId revCommitId,
         ObjectId computedChangeId,
         Change.Id cherryPickRevertChangeId,
         Instant timestamp,
-        Boolean workInProgress) {
+        Boolean workInProgress,
+        RevCommit baseCommit) {
       this.revCommitId = revCommitId;
       this.computedChangeId = computedChangeId;
       this.cherryPickRevertChangeId = cherryPickRevertChangeId;
       this.timestamp = timestamp;
       this.workInProgress = workInProgress;
+      this.baseCommit = baseCommit;
     }
 
     @Override
@@ -577,7 +589,8 @@
               change.getId(),
               computedChangeId,
               cherryPickRevertChangeId,
-              workInProgress);
+              workInProgress,
+              Optional.ofNullable(baseCommit));
       // save the commit as base for next cherryPick of that branch
       cherryPickInput.base =
           changeNotesFactory