Require branches to always start from commits

When creating a new branch, require that the branch points to a
commit object, and not to another type such as tag, tree, or blob.

Bug: issue 575
Change-Id: Ia0ebd25eb8d67fc113dee5a74fd51454f4bf180f
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce 2010-06-16 19:20:12 -07:00
parent 7187981def
commit 5710504c4e
2 changed files with 43 additions and 5 deletions

View File

@ -107,7 +107,19 @@ class AddBranch extends Handler<ListBranchesResult> {
try {
final ObjectId revid = parseStartingRevision(repo);
final RevWalk rw = verifyConnected(repo, revid);
final RevObject object = rw.parseAny(revid);
RevObject object = rw.parseAny(revid);
if (refname.startsWith(Constants.R_HEADS)) {
// Ensure that what we start the branch from is a commit. If we
// were given a tag, deference to the commit instead.
//
try {
object = rw.parseCommit(object);
} catch (IncorrectObjectTypeException notCommit) {
throw new IllegalStateException(startingRevision + " not a commit");
}
}
if (!refControl.canCreate(rw, object)) {
throw new IllegalStateException("Cannot create " + refname);
}
@ -115,7 +127,7 @@ class AddBranch extends Handler<ListBranchesResult> {
try {
final RefUpdate u = repo.updateRef(refname);
u.setExpectedOldObjectId(ObjectId.zeroId());
u.setNewObjectId(revid);
u.setNewObjectId(object.copy());
u.setRefLogIdent(identifiedUser.newRefLogIdent());
u.setRefLogMessage("created via web from " + startingRevision, false);
final RefUpdate.Result result = u.update(rw);

View File

@ -36,13 +36,11 @@ import com.google.gerrit.reviewdb.PatchSetInfo;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.RevId;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.TrackingId;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.TrackingFooter;
import com.google.gerrit.server.config.TrackingFooters;
import com.google.gerrit.server.mail.CreateChangeSender;
import com.google.gerrit.server.mail.EmailException;
@ -57,6 +55,7 @@ import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@ -471,7 +470,7 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
}
private void parseCreate(final ReceiveCommand cmd) {
final RevObject obj;
RevObject obj;
try {
obj = rp.getRevWalk().parseAny(cmd.getNewId());
} catch (IOException err) {
@ -481,6 +480,10 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
return;
}
if (isHead(cmd) && !isCommit(cmd)) {
return;
}
RefControl ctl = projectControl.controlForRef(cmd.getRefName());
if (ctl.canCreate(rp.getRevWalk(), obj)) {
validateNewCommits(ctl, cmd);
@ -493,6 +496,10 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
private void parseUpdate(final ReceiveCommand cmd) {
RefControl ctl = projectControl.controlForRef(cmd.getRefName());
if (ctl.canUpdate()) {
if (isHead(cmd) && !isCommit(cmd)) {
return;
}
validateNewCommits(ctl, cmd);
// Let the core receive process handle it
} else {
@ -500,6 +507,25 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
}
}
private boolean isCommit(final ReceiveCommand cmd) {
RevObject obj;
try {
obj = rp.getRevWalk().parseAny(cmd.getNewId());
} catch (IOException err) {
log.error("Invalid object " + cmd.getNewId().name() + " for "
+ cmd.getRefName(), err);
reject(cmd, "invalid object");
return false;
}
if (obj instanceof RevCommit) {
return true;
} else {
reject(cmd, "not a commit");
return false;
}
}
private void parseDelete(final ReceiveCommand cmd) {
RefControl ctl = projectControl.controlForRef(cmd.getRefName());
if (ctl.canDelete()) {