Merge "Attach o=STAR on change list queries in frontend."
diff --git a/java/com/google/gerrit/server/patch/BaseCommitUtil.java b/java/com/google/gerrit/server/patch/BaseCommitUtil.java
index 9a103cd..a264793 100644
--- a/java/com/google/gerrit/server/patch/BaseCommitUtil.java
+++ b/java/com/google/gerrit/server/patch/BaseCommitUtil.java
@@ -26,13 +26,11 @@
 import java.io.IOException;
 import java.util.Optional;
 import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevWalk;
 
 /** A utility class for computing the base commit / parent for a specific patchset commit. */
@@ -51,7 +49,8 @@
     this.repoManager = repoManager;
   }
 
-  RevObject getBaseCommit(Project.NameKey project, ObjectId newCommit, @Nullable Integer parentNum)
+  @Nullable
+  RevCommit getBaseCommit(Project.NameKey project, ObjectId newCommit, @Nullable Integer parentNum)
       throws IOException {
     try (Repository repo = repoManager.openRepository(project);
         ObjectInserter ins = newInserter(repo);
@@ -89,10 +88,12 @@
    *     commitId} has a single parent, it will be returned.
    * @param commitId 20 bytes commitId SHA-1 hash.
    * @return Returns the parent commit of the commit represented by the commitId parameter. Note
-   *     that auto-merge is not supported for commits having more than two parents.
+   *     that auto-merge is not supported for commits having more than two parents. If the commit
+   *     has no parents (initial commit) or more than 2 parents {@code null} is returned as the
+   *     parent commit.
    */
   @Nullable
-  RevObject getParentCommit(
+  RevCommit getParentCommit(
       Repository repo,
       ObjectInserter ins,
       RevWalk rw,
@@ -102,7 +103,7 @@
     RevCommit current = rw.parseCommit(commitId);
     switch (current.getParentCount()) {
       case 0:
-        return rw.parseAny(emptyTree(ins));
+        return null;
       case 1:
         return current.getParent(0);
       default:
@@ -146,10 +147,4 @@
   private ObjectInserter newInserter(Repository repo) {
     return saveAutomerge ? repo.newObjectInserter() : new InMemoryInserter(repo);
   }
-
-  private static ObjectId emptyTree(ObjectInserter ins) throws IOException {
-    ObjectId id = ins.insert(Constants.OBJ_TREE, new byte[] {});
-    ins.flush();
-    return id;
-  }
 }
diff --git a/java/com/google/gerrit/server/patch/DiffOperationsImpl.java b/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
index 86f122e..2606d66 100644
--- a/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
+++ b/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
@@ -55,6 +55,7 @@
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.util.io.DisabledOutputStream;
 
@@ -488,7 +489,16 @@
     DiffParameters.Builder result =
         DiffParameters.builder().project(project).newCommit(newCommit).parent(parent);
     if (parent > 0) {
-      result.baseCommit(baseCommitUtil.getBaseCommit(project, newCommit, parent));
+      RevCommit baseCommit = baseCommitUtil.getBaseCommit(project, newCommit, parent);
+      if (baseCommit == null) {
+        // The specified parent doesn't exist or is not supported, fall back to comparing against
+        // the root.
+        result.baseCommit(ObjectId.zeroId());
+        result.comparisonType(ComparisonType.againstRoot());
+        return result.build();
+      }
+
+      result.baseCommit(baseCommit);
       result.comparisonType(ComparisonType.againstParent(parent));
       return result.build();
     }
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/ListCommitFilesIT.java b/javatests/com/google/gerrit/acceptance/rest/project/ListCommitFilesIT.java
index 3ac2d10..5f02af1 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/ListCommitFilesIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/ListCommitFilesIT.java
@@ -15,17 +15,21 @@
 package com.google.gerrit.acceptance.rest.project;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.GitUtil.assertPushOk;
 import static com.google.gerrit.acceptance.GitUtil.getChangeId;
 import static com.google.gerrit.acceptance.GitUtil.pushHead;
 
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.PushOneCommit;
 import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.TestProjectInput;
+import com.google.gerrit.entities.Patch;
 import com.google.gerrit.extensions.common.FileInfo;
 import com.google.gson.reflect.TypeToken;
 import java.lang.reflect.Type;
 import java.util.Map;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.PushResult;
 import org.junit.Test;
 
 public class ListCommitFilesIT extends AbstractDaemonTest {
@@ -87,4 +91,31 @@
 
     assertThat(files1).isEqualTo(files2);
   }
+
+  @Test
+  @TestProjectInput(createEmptyCommit = false)
+  public void listFilesOfInitialCommitAgainstFirstParent() throws Exception {
+    // create initial commit with no parent and push it directly to refs/heads/master
+    RevCommit c =
+        testRepo
+            .commit()
+            .message("Initial commit")
+            .add("a.txt", "aContent")
+            .add("b.txt", "bContent")
+            .create();
+    testRepo.reset(c);
+    PushResult r = pushHead(testRepo, "refs/heads/master", false);
+    assertPushOk(r, "refs/heads/master");
+
+    // Request diff against first parent although the initial commit doesn't have a parent
+    RestResponse response =
+        userRestSession.get(
+            "/projects/" + project.get() + "/commits/" + c.name() + "/files/?parent=1");
+    response.assertOK();
+    Type type = new TypeToken<Map<String, FileInfo>>() {}.getType();
+    Map<String, FileInfo> files = newGson().fromJson(response.getReader(), type);
+    response.consume();
+
+    assertThat(files.keySet()).containsExactly(Patch.COMMIT_MSG, "a.txt", "b.txt");
+  }
 }
diff --git a/plugins/BUILD b/plugins/BUILD
index 39560c5..b9c51e3 100644
--- a/plugins/BUILD
+++ b/plugins/BUILD
@@ -62,6 +62,7 @@
     "//java/com/google/gerrit/server/data",
     "//java/com/google/gerrit/server/git/receive",
     "//java/com/google/gerrit/server/logging",
+    "//java/com/google/gerrit/server/rules/prolog",
     "//java/com/google/gerrit/server/schema",
     "//java/com/google/gerrit/server/util/time",
     "//java/com/google/gerrit/proto",