Add commit check for head references

Make sure all refs/heads/* point to a commit object.

Change-Id: I9c7cf347aaf63d5ef604d520c2383c6cf3043890
Signed-off-by: Zhen Chen <czhen@google.com>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java
index 8d223c8..804d744 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java
@@ -240,4 +240,30 @@
 		assertEquals(errors.getMissingObjects().size(), 1);
 		assertEquals(errors.getMissingObjects().iterator().next(), blobId);
 	}
+
+	@Test
+	public void testNonCommitHead() throws Exception {
+		RevCommit commit0 = git.commit().message("0").create();
+		StringBuilder b = new StringBuilder();
+		b.append("object ");
+		b.append(commit0.getName());
+		b.append('\n');
+		b.append("type commit\n");
+		b.append("tag test-tag\n");
+		b.append("tagger A. U. Thor <author@localhost> 1 +0000\n");
+
+		byte[] data = encodeASCII(b.toString());
+		ObjectId tagId = ins.insert(Constants.OBJ_TAG, data);
+		ins.flush();
+
+		git.update("master", tagId);
+
+		DfsFsck fsck = new DfsFsck(repo);
+		FsckError errors = fsck.check(null);
+		assertEquals(errors.getCorruptObjects().size(), 0);
+		assertEquals(errors.getNonCommitHeads().size(), 1);
+		assertEquals(errors.getNonCommitHeads().iterator().next(),
+				"refs/heads/master");
+	}
+
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java
index b7aac16..588ed9b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java
@@ -128,6 +128,8 @@
 
 	private final Set<CorruptIndex> corruptIndices = new HashSet<>();
 
+	private final Set<String> nonCommitHeads = new HashSet<>();
+
 	/** @return corrupt objects from all pack files. */
 	public Set<CorruptObject> getCorruptObjects() {
 		return corruptObjects;
@@ -142,4 +144,9 @@
 	public Set<CorruptIndex> getCorruptIndices() {
 		return corruptIndices;
 	}
+
+	/** @return refs/heads/* point to non-commit object. */
+	public Set<String> getNonCommitHeads() {
+		return nonCommitHeads;
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
index 9549dbb..f90ba7d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
@@ -52,6 +52,7 @@
 import org.eclipse.jgit.internal.fsck.FsckError.CorruptIndex;
 import org.eclipse.jgit.internal.fsck.FsckPackParser;
 import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectChecker;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
@@ -123,6 +124,13 @@
 				for (Ref r : repo.getAllRefs().values()) {
 					try {
 						RevObject tip = ow.parseAny(r.getObjectId());
+						if (r.getLeaf().getName().startsWith(Constants.R_HEADS)) {
+							// check if heads point to a commit object
+							if (tip.getType() != Constants.OBJ_COMMIT) {
+								errors.getNonCommitHeads()
+										.add(r.getLeaf().getName());
+							}
+						}
 						ow.markStart(tip);
 						ow.checkConnectivity();
 						ow.markUninteresting(tip);