Fix pushing a series of changes to a non-existing branch with createNewChangeForAllNotInTarget

Pushing changes for review requires that the target branch exists, but
there is an exception for the branch to which HEAD in the remote
repository points to and for refs/meta/config. Pushing for review to
these branches is allowed even if the branch does not exist yet. This
didn't work if createNewChangeForAllNotInTarget was true because in
this case we tried to read the non-existing target branch as base and
as result the push was rejected. If the target branch doesn't exist yet
all pushed commits should always result in new changes and the setting
of createNewChangeForAllNotInTarget shouldn't matter.

Change-Id: I19a0443929d3774619a2682352fd37bca3eac321
Signed-off-by: Edwin Kempin <ekempin@google.com>
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index c747533..48df354 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -1753,9 +1753,10 @@
           reject(cmd, "cannot use merged with base");
           return;
         }
-        RevCommit branchTip = readBranchTip(cmd, magicBranch.dest);
+        RevCommit branchTip = readBranchTip(magicBranch.dest);
         if (branchTip == null) {
-          return; // readBranchTip already rejected cmd.
+          reject(cmd, magicBranch.dest.get() + " not found");
+          return;
         }
         if (!walk.isMergedInto(tip, branchTip)) {
           reject(cmd, "not merged into branch");
@@ -1793,12 +1794,21 @@
           }
         }
       } else if (newChangeForAllNotInTarget) {
-        RevCommit branchTip = readBranchTip(cmd, magicBranch.dest);
-        if (branchTip == null) {
-          return; // readBranchTip already rejected cmd.
+        RevCommit branchTip = readBranchTip(magicBranch.dest);
+        if (branchTip != null) {
+          magicBranch.baseCommit = Collections.singletonList(branchTip);
+          logger.atFine().log("Set baseCommit = %s", magicBranch.baseCommit.get(0).name());
+        } else {
+          // The target branch does not exist. Usually pushing changes for review requires that the
+          // target branch exists, but there is an exception for the branch to which HEAD points to
+          // and for refs/meta/config. Pushing for review to these branches is allowed even if the
+          // branch does not exist yet. This allows to push initial code for review to an empty
+          // repository and to review an initial project configuration.
+          if (!ref.equals(readHEAD(repo)) && !ref.equals(RefNames.REFS_CONFIG)) {
+            reject(cmd, magicBranch.dest.get() + " not found");
+            return;
+          }
         }
-        magicBranch.baseCommit = Collections.singletonList(branchTip);
-        logger.atFine().log("Set baseCommit = %s", magicBranch.baseCommit.get(0).name());
       }
     } catch (IOException ex) {
       logger.atWarning().withCause(ex).log(
@@ -1870,10 +1880,9 @@
     }
   }
 
-  private RevCommit readBranchTip(ReceiveCommand cmd, Branch.NameKey branch) throws IOException {
+  private RevCommit readBranchTip(Branch.NameKey branch) throws IOException {
     Ref r = allRefs().get(branch.get());
     if (r == null) {
-      reject(cmd, branch.get() + " not found");
       return null;
     }
     return receivePack.getRevWalk().parseCommit(r.getObjectId());
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 228784b..254b6ac 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -221,6 +221,18 @@
   @Test
   @TestProjectInput(createEmptyCommit = false)
   public void pushInitialCommitSeriesForMasterBranch() throws Exception {
+    testPushInitialCommitSeriesForMasterBranch();
+  }
+
+  @Test
+  @TestProjectInput(createEmptyCommit = false)
+  public void pushInitialCommitSeriesForMasterBranchWithCreateNewChangeForAllNotInTarget()
+      throws Exception {
+    enableCreateNewChangeForAllNotInTarget();
+    testPushInitialCommitSeriesForMasterBranch();
+  }
+
+  private void testPushInitialCommitSeriesForMasterBranch() throws Exception {
     RevCommit c = testRepo.commit().message("Initial commit").insertChangeId().create();
     String id = GitUtil.getChangeId(testRepo, c).get();
     testRepo.reset(c);