Merge changes from topic 'rebase-cleanup'

* changes:
  RebaseChange: Minor cleanup
  Rebase: Implement hasOneParent using commit parents
  Rebase: Use Ints.tryParse instead of catching exception
  Rebase: Minor cleanup
  Rebase: Extract a method to find base revision
  Rebase: Check commit ancestry using git
This commit is contained in:
Dave Borowitz
2015-05-21 15:30:25 +00:00
committed by Gerrit Code Review
3 changed files with 275 additions and 280 deletions

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.server.change;
import com.google.common.primitives.Ints;
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.extensions.api.changes.RebaseInput;
import com.google.gerrit.extensions.client.ListChangesOption;
@@ -26,9 +27,10 @@ import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Status;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetAncestor;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
@@ -37,26 +39,32 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
@Singleton
public class Rebase implements RestModifyView<RevisionResource, RebaseInput>,
UiAction<RevisionResource> {
private static final Logger log =
LoggerFactory.getLogger(Rebase.class);
private static final Logger log = LoggerFactory.getLogger(Rebase.class);
private final GitRepositoryManager repoManager;
private final Provider<RebaseChange> rebaseChange;
private final ChangeJson json;
private final Provider<ReviewDb> dbProvider;
@Inject
public Rebase(Provider<RebaseChange> rebaseChange, ChangeJson json,
public Rebase(GitRepositoryManager repoManager,
Provider<RebaseChange> rebaseChange,
ChangeJson json,
Provider<ReviewDb> dbProvider) {
this.repoManager = repoManager;
this.rebaseChange = rebaseChange;
this.json = json
.addOption(ListChangesOption.CURRENT_REVISION)
@@ -70,61 +78,19 @@ public class Rebase implements RestModifyView<RevisionResource, RebaseInput>,
ResourceConflictException, EmailException, OrmException, IOException {
ChangeControl control = rsrc.getControl();
Change change = rsrc.getChange();
if (!control.canRebase()) {
throw new AuthException("rebase not permitted");
} else if (!change.getStatus().isOpen()) {
throw new ResourceConflictException("change is "
+ change.getStatus().name().toLowerCase());
} else if (!hasOneParent(rsrc.getPatchSet().getId())) {
throw new ResourceConflictException(
"cannot rebase merge commits or commit with no ancestor");
}
String baseRev = null;
if (input != null && input.base != null) {
String base = input.base.trim();
do {
if (base.equals("")) {
// remove existing dependency to other patch set
baseRev = change.getDest().get();
break;
}
ReviewDb db = dbProvider.get();
PatchSet basePatchSet = parseBase(base);
if (basePatchSet == null) {
throw new ResourceConflictException("base revision is missing: " + base);
} else if (!rsrc.getControl().isPatchVisible(basePatchSet, db)) {
throw new AuthException("base revision not accessible: " + base);
} else if (change.getId().equals(basePatchSet.getId().getParentKey())) {
throw new ResourceConflictException("cannot depend on self");
}
Change baseChange = db.changes().get(basePatchSet.getId().getParentKey());
if (baseChange != null) {
if (!baseChange.getProject().equals(change.getProject())) {
throw new ResourceConflictException("base change is in wrong project: "
+ baseChange.getProject());
} else if (!baseChange.getDest().equals(change.getDest())) {
throw new ResourceConflictException("base change is targetting wrong branch: "
+ baseChange.getDest());
} else if (baseChange.getStatus() == Status.ABANDONED) {
throw new ResourceConflictException("base change is abandoned: "
+ baseChange.getKey());
} else if (isDescendantOf(baseChange.getId(), rsrc.getPatchSet().getRevision())) {
throw new ResourceConflictException("base change " + baseChange.getKey()
+ " is a descendant of the current "
+ " change - recursion not allowed");
}
baseRev = basePatchSet.getRevision().get();
break;
}
} while (false); // just wanted to use the break statement
}
try {
rebaseChange.get().rebase(change, rsrc.getPatchSet().getId(),
rsrc.getUser(), baseRev);
try (Repository repo = repoManager.openRepository(change.getProject());
RevWalk rw = new RevWalk(repo)) {
if (!control.canRebase()) {
throw new AuthException("rebase not permitted");
} else if (!change.getStatus().isOpen()) {
throw new ResourceConflictException("change is "
+ change.getStatus().name().toLowerCase());
} else if (!hasOneParent(rw, rsrc.getPatchSet())) {
throw new ResourceConflictException(
"cannot rebase merge commits or commit with no ancestor");
}
rebaseChange.get().rebase(repo, rw, change, rsrc.getPatchSet().getId(),
rsrc.getUser(), findBaseRev(rw, rsrc, input));
} catch (InvalidChangeOperationException e) {
throw new ResourceConflictException(e.getMessage());
} catch (NoSuchChangeException e) {
@@ -134,89 +100,118 @@ public class Rebase implements RestModifyView<RevisionResource, RebaseInput>,
return json.format(change.getId());
}
private boolean isDescendantOf(Change.Id child, RevId ancestor)
throws OrmException {
ReviewDb db = dbProvider.get();
ArrayList<RevId> parents = new ArrayList<>();
parents.add(ancestor);
while (!parents.isEmpty()) {
RevId parent = parents.remove(0);
// get direct descendants of change
for (PatchSetAncestor desc : db.patchSetAncestors().descendantsOf(parent)) {
PatchSet descPatchSet = db.patchSets().get(desc.getPatchSet());
Change.Id descChangeId = descPatchSet.getId().getParentKey();
if (child.equals(descChangeId)) {
PatchSet.Id descCurrentPatchSetId =
db.changes().get(descChangeId).currentPatchSetId();
// it's only bad if the descendant patch set is current
return descPatchSet.getId().equals(descCurrentPatchSetId);
} else {
// process indirect descendants as well
parents.add(descPatchSet.getRevision());
}
}
private String findBaseRev(RevWalk rw, RevisionResource rsrc,
RebaseInput input) throws AuthException, ResourceConflictException,
OrmException, IOException {
if (input == null || input.base == null) {
return null;
}
return false;
Change change = rsrc.getChange();
String base = input.base.trim();
if (base.equals("")) {
// remove existing dependency to other patch set
return change.getDest().get();
}
ReviewDb db = dbProvider.get();
PatchSet basePatchSet = parseBase(base);
if (basePatchSet == null) {
throw new ResourceConflictException("base revision is missing: " + base);
} else if (!rsrc.getControl().isPatchVisible(basePatchSet, db)) {
throw new AuthException("base revision not accessible: " + base);
} else if (change.getId().equals(basePatchSet.getId().getParentKey())) {
throw new ResourceConflictException("cannot depend on self");
}
Change baseChange = db.changes().get(basePatchSet.getId().getParentKey());
if (baseChange == null) {
return null;
}
if (!baseChange.getProject().equals(change.getProject())) {
throw new ResourceConflictException(
"base change is in wrong project: " + baseChange.getProject());
} else if (!baseChange.getDest().equals(change.getDest())) {
throw new ResourceConflictException(
"base change is targeting wrong branch: " + baseChange.getDest());
} else if (baseChange.getStatus() == Status.ABANDONED) {
throw new ResourceConflictException(
"base change is abandoned: " + baseChange.getKey());
} else if (isMergedInto(rw, rsrc.getPatchSet(), basePatchSet)) {
throw new ResourceConflictException(
"base change " + baseChange.getKey()
+ " is a descendant of the current change - recursion not allowed");
}
return basePatchSet.getRevision().get();
}
private PatchSet parseBase(final String base) throws OrmException {
private boolean isMergedInto(RevWalk rw, PatchSet base, PatchSet tip)
throws IOException {
ObjectId baseId = ObjectId.fromString(base.getRevision().get());
ObjectId tipId = ObjectId.fromString(tip.getRevision().get());
return rw.isMergedInto(rw.parseCommit(baseId), rw.parseCommit(tipId));
}
private PatchSet parseBase(String base) throws OrmException {
ReviewDb db = dbProvider.get();
PatchSet.Id basePatchSetId = PatchSet.Id.fromRef(base);
if (basePatchSetId != null) {
// try parsing the base as a ref string
// Try parsing the base as a ref string.
return db.patchSets().get(basePatchSetId);
}
// try parsing base as a change number (assume current patch set)
// Try parsing base as a change number (assume current patch set).
PatchSet basePatchSet = null;
try {
Change.Id baseChangeId = Change.Id.parse(base);
if (baseChangeId != null) {
for (PatchSet ps : db.patchSets().byChange(baseChangeId)) {
if (basePatchSet == null || basePatchSet.getId().get() < ps.getId().get()){
basePatchSet = ps;
}
}
}
} catch (NumberFormatException e) { // probably a SHA1
}
// try parsing as SHA1
if (basePatchSet == null) {
for (PatchSet ps : db.patchSets().byRevision(new RevId(base))) {
if (basePatchSet == null || basePatchSet.getId().get() < ps.getId().get()) {
Integer baseChangeId = Ints.tryParse(base);
if (baseChangeId != null) {
for (PatchSet ps : db.patchSets().byChange(new Change.Id(baseChangeId))) {
if (basePatchSet == null
|| basePatchSet.getId().get() < ps.getId().get()) {
basePatchSet = ps;
}
}
if (basePatchSet != null) {
return basePatchSet;
}
}
// Try parsing as SHA-1.
for (PatchSet ps : db.patchSets().byRevision(new RevId(base))) {
if (basePatchSet == null
|| basePatchSet.getId().get() < ps.getId().get()) {
basePatchSet = ps;
}
}
return basePatchSet;
}
private boolean hasOneParent(final PatchSet.Id patchSetId) {
try {
// prevent rebase of exotic changes (merge commit, no ancestor).
return (dbProvider.get().patchSetAncestors()
.ancestorsOf(patchSetId).toList().size() == 1);
} catch (OrmException e) {
log.error("Failed to get ancestors of patch set "
+ patchSetId.toRefName(), e);
return false;
}
private boolean hasOneParent(RevWalk rw, PatchSet ps) throws IOException {
// Prevent rebase of exotic changes (merge commit, no ancestor).
RevCommit c = rw.parseCommit(ObjectId.fromString(ps.getRevision().get()));
return c.getParentCount() == 1;
}
@Override
public UiAction.Description getDescription(RevisionResource resource) {
Project.NameKey project = resource.getChange().getProject();
boolean visible = resource.getChange().getStatus().isOpen()
&& resource.isCurrent()
&& resource.getControl().canRebase();
if (visible) {
try (Repository repo = repoManager.openRepository(project);
RevWalk rw = new RevWalk(repo)) {
visible = hasOneParent(rw, resource.getPatchSet());
} catch (IOException e) {
log.error("Failed to get ancestors of patch set "
+ resource.getPatchSet().getId(), e);
visible = false;
}
}
UiAction.Description descr = new UiAction.Description()
.setLabel("Rebase")
.setTitle("Rebase onto tip of branch or parent change")
.setVisible(resource.getChange().getStatus().isOpen()
&& resource.isCurrent()
&& resource.getControl().canRebase()
&& hasOneParent(resource.getPatchSet().getId()));
.setVisible(visible);
if (descr.isVisible()) {
// Disable the rebase button in the RebaseDialog if
// the change cannot be rebased.

View File

@@ -67,12 +67,12 @@ public class RebaseChange {
private final PatchSetInserter.Factory patchSetInserterFactory;
@Inject
RebaseChange(final ChangeControl.GenericFactory changeControlFactory,
final Provider<ReviewDb> db,
@GerritPersonIdent final PersonIdent myIdent,
final GitRepositoryManager gitManager,
final MergeUtil.Factory mergeUtilFactory,
final PatchSetInserter.Factory patchSetInserterFactory) {
RebaseChange(ChangeControl.GenericFactory changeControlFactory,
Provider<ReviewDb> db,
@GerritPersonIdent PersonIdent myIdent,
GitRepositoryManager gitManager,
MergeUtil.Factory mergeUtilFactory,
PatchSetInserter.Factory patchSetInserterFactory) {
this.changeControlFactory = changeControlFactory;
this.db = db;
this.gitManager = gitManager;
@@ -82,64 +82,64 @@ public class RebaseChange {
}
/**
* Rebases the change of the given patch set.
*
* Rebase the change of the given patch set.
* <p>
* It is verified that the current user is allowed to do the rebase.
*
* <p>
* If the patch set has no dependency to an open change, then the change is
* rebased on the tip of the destination branch.
*
* <p>
* If the patch set depends on an open change, it is rebased on the latest
* patch set of this change.
*
* <p>
* The rebased commit is added as new patch set to the change.
*
* <p>
* E-mail notification and triggering of hooks happens for the creation of the
* new patch set.
*
* @param change the change to perform the rebase for
* @param patchSetId the id of the patch set
* @param uploader the user that creates the rebased patch set
* @param newBaseRev the commit that should be the new base
* @throws NoSuchChangeException thrown if the change to which the patch set
* belongs does not exist or is not visible to the user
* @throws EmailException thrown if sending the e-mail to notify about the new
* patch set fails
* @throws OrmException thrown in case accessing the database fails
* @throws IOException thrown if rebase is not possible or not needed
* @throws InvalidChangeOperationException thrown if rebase is not allowed
* @param git the repository.
* @param rw the RevWalk.
* @param change the change to rebase.
* @param patchSetId the patch set ID to rebase.
* @param uploader the user that creates the rebased patch set.
* @param newBaseRev the commit that should be the new base.
* @throws NoSuchChangeException if the change to which the patch set belongs
* does not exist or is not visible to the user.
* @throws EmailException if sending the e-mail to notify about the new patch
* set fails.
* @throws OrmException if accessing the database fails.
* @throws IOException if accessing the repository fails.
* @throws InvalidChangeOperationException if rebase is not possible or not
* allowed.
*/
public void rebase(Change change, PatchSet.Id patchSetId, final IdentifiedUser uploader,
final String newBaseRev) throws NoSuchChangeException, EmailException, OrmException,
IOException, InvalidChangeOperationException {
final Change.Id changeId = patchSetId.getParentKey();
final ChangeControl changeControl =
public void rebase(Repository git, RevWalk rw, Change change,
PatchSet.Id patchSetId, IdentifiedUser uploader, String newBaseRev)
throws NoSuchChangeException, EmailException, OrmException, IOException,
InvalidChangeOperationException {
Change.Id changeId = patchSetId.getParentKey();
ChangeControl changeControl =
changeControlFactory.validateFor(change, uploader);
if (!changeControl.canRebase()) {
throw new InvalidChangeOperationException(
"Cannot rebase: New patch sets are not allowed to be added to change: "
+ changeId.toString());
throw new InvalidChangeOperationException("Cannot rebase: New patch sets"
+ " are not allowed to be added to change: " + changeId);
}
try (Repository git = gitManager.openRepository(change.getProject());
RevWalk rw = new RevWalk(git);
ObjectInserter inserter = git.newObjectInserter()) {
try (ObjectInserter inserter = git.newObjectInserter()) {
String baseRev = newBaseRev;
if (baseRev == null) {
baseRev =
findBaseRevision(patchSetId, db.get(), change.getDest(), git, rw);
baseRev = findBaseRevision(
patchSetId, db.get(), change.getDest(), git, rw);
}
ObjectId baseObjectId = git.resolve(baseRev);
if (baseObjectId == null) {
throw new InvalidChangeOperationException(
"Cannot rebase: Failed to resolve baseRev: " + baseRev);
}
final RevCommit baseCommit = rw.parseCommit(baseObjectId);
RevCommit baseCommit = rw.parseCommit(baseObjectId);
PersonIdent committerIdent =
uploader.newCommitterIdent(TimeUtil.nowTs(),
serverTimeZone);
uploader.newCommitterIdent(TimeUtil.nowTs(), serverTimeZone);
rebase(git, rw, inserter, patchSetId, change,
rebase(git, rw, inserter, change, patchSetId,
uploader, baseCommit, mergeUtilFactory.create(
changeControl.getProjectControl().getProjectState(), true),
committerIdent, true, ValidatePolicy.GERRIT);
@@ -148,146 +148,151 @@ public class RebaseChange {
}
}
/**
* Finds the revision of commit on which the given patch set should be based.
*
* @param patchSetId the id of the patch set for which the new base commit
* should be found
* @param db the ReviewDb
* @param destBranch the destination branch
* @param git the repository
* @param rw the RevWalk
* @return the revision of commit on which the given patch set should be based
* @throws InvalidChangeOperationException if rebase is not possible or not
* allowed
* @throws IOException thrown if accessing the repository fails
* @throws OrmException thrown if accessing the database fails
*/
private static String findBaseRevision(PatchSet.Id patchSetId,
ReviewDb db, Branch.NameKey destBranch, Repository git, RevWalk rw)
throws InvalidChangeOperationException, IOException, OrmException {
/**
* Find the commit onto which a patch set should be rebased.
* <p>
* This is defined as the latest patch set of the change corresponding to
* this commit's parent, or the destination branch tip in the case where the
* parent's change is merged.
*
* @param patchSetId patch set ID for which the new base commit should be
* found.
* @param db the ReviewDb.
* @param destBranch the destination branch.
* @param git the repository.
* @param rw the RevWalk.
* @return the commit onto which the patch set should be rebased.
* @throws InvalidChangeOperationException if rebase is not possible or not
* allowed.
* @throws IOException if accessing the repository fails.
* @throws OrmException if accessing the database fails.
*/
private static String findBaseRevision(PatchSet.Id patchSetId,
ReviewDb db, Branch.NameKey destBranch, Repository git, RevWalk rw)
throws InvalidChangeOperationException, IOException, OrmException {
String baseRev = null;
String baseRev = null;
PatchSet patchSet = db.patchSets().get(patchSetId);
if (patchSet == null) {
throw new InvalidChangeOperationException(
"Patch set " + patchSetId + " not found");
}
RevCommit commit = rw.parseCommit(
ObjectId.fromString(patchSet.getRevision().get()));
PatchSet patchSet = db.patchSets().get(patchSetId);
if (patchSet == null) {
throw new InvalidChangeOperationException(
"Patch set " + patchSetId + " not found");
}
RevCommit commit = rw.parseCommit(
ObjectId.fromString(patchSet.getRevision().get()));
if (commit.getParentCount() > 1) {
throw new InvalidChangeOperationException(
"Cannot rebase a change with multiple parents.");
} else if (commit.getParentCount() == 0) {
throw new InvalidChangeOperationException(
"Cannot rebase a change without any parents"
+ " (is this the initial commit?).");
}
RevId parentRev = new RevId(commit.getParent(0).name());
for (PatchSet depPatchSet : db.patchSets().byRevision(parentRev)) {
Change.Id depChangeId = depPatchSet.getId().getParentKey();
Change depChange = db.changes().get(depChangeId);
if (!depChange.getDest().equals(destBranch)) {
continue;
}
if (depChange.getStatus() == Status.ABANDONED) {
throw new InvalidChangeOperationException("Cannot rebase a change with an abandoned parent: "
+ depChange.getKey().toString());
}
if (depChange.getStatus().isOpen()) {
if (depPatchSet.getId().equals(depChange.currentPatchSetId())) {
throw new InvalidChangeOperationException(
"Change is already based on the latest patch set of the dependent change.");
}
PatchSet latestDepPatchSet =
db.patchSets().get(depChange.currentPatchSetId());
baseRev = latestDepPatchSet.getRevision().get();
}
break;
}
if (baseRev == null) {
// We are dependent on a merged PatchSet or have no PatchSet
// dependencies at all.
Ref destRef = git.getRef(destBranch.get());
if (destRef == null) {
throw new InvalidChangeOperationException(
"The destination branch does not exist: " + destBranch.get());
}
baseRev = destRef.getObjectId().getName();
if (baseRev.equals(parentRev.get())) {
throw new InvalidChangeOperationException("Change is already up to date.");
}
}
return baseRev;
if (commit.getParentCount() > 1) {
throw new InvalidChangeOperationException(
"Cannot rebase a change with multiple parents.");
} else if (commit.getParentCount() == 0) {
throw new InvalidChangeOperationException(
"Cannot rebase a change without any parents"
+ " (is this the initial commit?).");
}
RevId parentRev = new RevId(commit.getParent(0).name());
for (PatchSet depPatchSet : db.patchSets().byRevision(parentRev)) {
Change.Id depChangeId = depPatchSet.getId().getParentKey();
Change depChange = db.changes().get(depChangeId);
if (!depChange.getDest().equals(destBranch)) {
continue;
}
if (depChange.getStatus() == Status.ABANDONED) {
throw new InvalidChangeOperationException(
"Cannot rebase a change with an abandoned parent: "
+ depChange.getKey());
}
if (depChange.getStatus().isOpen()) {
if (depPatchSet.getId().equals(depChange.currentPatchSetId())) {
throw new InvalidChangeOperationException(
"Change is already based on the latest patch set of the"
+ " dependent change.");
}
PatchSet latestDepPatchSet =
db.patchSets().get(depChange.currentPatchSetId());
baseRev = latestDepPatchSet.getRevision().get();
}
break;
}
if (baseRev == null) {
// We are dependent on a merged PatchSet or have no PatchSet
// dependencies at all.
Ref destRef = git.getRef(destBranch.get());
if (destRef == null) {
throw new InvalidChangeOperationException(
"The destination branch does not exist: " + destBranch.get());
}
baseRev = destRef.getObjectId().getName();
if (baseRev.equals(parentRev.get())) {
throw new InvalidChangeOperationException(
"Change is already up to date.");
}
}
return baseRev;
}
/**
* Rebases the change of the given patch set on the given base commit.
*
* Rebase the change of the given patch set on the given base commit.
* <p>
* The rebased commit is added as new patch set to the change.
* <p>
* E-mail notification and triggering of hooks is only done for the creation
* of the new patch set if {@code sendEmail} and {@code runHooks} are true,
* respectively.
*
* E-mail notification and triggering of hooks is only done for the creation of
* the new patch set if `sendEmail` and `runHooks` are set to true.
*
* @param git the repository
* @param revWalk the RevWalk
* @param inserter the object inserter
* @param patchSetId the id of the patch set
* @param change the change that should be rebased
* @param uploader the user that creates the rebased patch set
* @param baseCommit the commit that should be the new base
* @param mergeUtil merge utilities for the destination project
* @param committerIdent the committer's identity
* @param runHooks if hooks should be run for the new patch set
* @param validate if commit validation should be run for the new patch set
* @return the new patch set which is based on the given base commit
* @throws NoSuchChangeException thrown if the change to which the patch set
* belongs does not exist or is not visible to the user
* @throws OrmException thrown in case accessing the database fails
* @throws IOException thrown if rebase is not possible or not needed
* @throws InvalidChangeOperationException thrown if rebase is not allowed
* @param git the repository.
* @param inserter the object inserter.
* @param change the change to rebase.
* @param patchSetId the patch set ID to rebase.
* @param uploader the user that creates the rebased patch set.
* @param baseCommit the commit that should be the new base.
* @param mergeUtil merge utilities for the destination project.
* @param committerIdent the committer's identity.
* @param runHooks if hooks should be run for the new patch set.
* @param validate if commit validation should be run for the new patch set.
* @param rw the RevWalk.
* @return the new patch set, which is based on the given base commit.
* @throws NoSuchChangeException if the change to which the patch set belongs
* does not exist or is not visible to the user.
* @throws OrmException if accessing the database fails.
* @throws IOException if rebase is not possible.
* @throws InvalidChangeOperationException if rebase is not possible or not
* allowed.
*/
public PatchSet rebase(final Repository git, final RevWalk revWalk,
final ObjectInserter inserter, final PatchSet.Id patchSetId,
final Change change, final IdentifiedUser uploader, final RevCommit baseCommit,
final MergeUtil mergeUtil, PersonIdent committerIdent,
boolean runHooks, ValidatePolicy validate)
throws NoSuchChangeException,
OrmException, IOException, InvalidChangeOperationException,
MergeConflictException {
public PatchSet rebase(Repository git, RevWalk rw,
ObjectInserter inserter, Change change, PatchSet.Id patchSetId,
IdentifiedUser uploader, RevCommit baseCommit, MergeUtil mergeUtil,
PersonIdent committerIdent, boolean runHooks, ValidatePolicy validate)
throws NoSuchChangeException, OrmException, IOException,
InvalidChangeOperationException, MergeConflictException {
if (!change.currentPatchSetId().equals(patchSetId)) {
throw new InvalidChangeOperationException("patch set is not current");
}
final PatchSet originalPatchSet = db.get().patchSets().get(patchSetId);
PatchSet originalPatchSet = db.get().patchSets().get(patchSetId);
final RevCommit rebasedCommit;
RevCommit rebasedCommit;
ObjectId oldId = ObjectId.fromString(originalPatchSet.getRevision().get());
ObjectId newId = rebaseCommit(git, inserter, revWalk.parseCommit(oldId),
ObjectId newId = rebaseCommit(git, inserter, rw.parseCommit(oldId),
baseCommit, mergeUtil, committerIdent);
rebasedCommit = revWalk.parseCommit(newId);
rebasedCommit = rw.parseCommit(newId);
final ChangeControl changeControl =
ChangeControl changeControl =
changeControlFactory.validateFor(change, uploader);
PatchSetInserter patchSetInserter = patchSetInserterFactory
.create(git, revWalk, changeControl, rebasedCommit)
.create(git, rw, changeControl, rebasedCommit)
.setValidatePolicy(validate)
.setDraft(originalPatchSet.isDraft())
.setUploader(uploader.getAccountId())
.setSendMail(false)
.setRunHooks(runHooks);
final PatchSet.Id newPatchSetId = patchSetInserter.getPatchSetId();
final ChangeMessage cmsg = new ChangeMessage(
PatchSet.Id newPatchSetId = patchSetInserter.getPatchSetId();
ChangeMessage cmsg = new ChangeMessage(
new ChangeMessage.Key(change.getId(),
ChangeUtil.messageUUID(db.get())), uploader.getAccountId(),
TimeUtil.nowTs(), patchSetId);
@@ -356,8 +361,8 @@ public class RebaseChange {
r.getPatchSet().getId(), r.getChange().getDest());
}
public boolean canRebase(Project.NameKey project,
PatchSet.Id patchSetId, Branch.NameKey branch) {
public boolean canRebase(Project.NameKey project, PatchSet.Id patchSetId,
Branch.NameKey branch) {
Repository git;
try {
git = gitManager.openRepository(project);
@@ -367,12 +372,7 @@ public class RebaseChange {
return false;
}
try (RevWalk rw = new RevWalk(git)) {
findBaseRevision(
patchSetId,
db.get(),
branch,
git,
rw);
findBaseRevision(patchSetId, db.get(), branch, git, rw);
return true;
} catch (InvalidChangeOperationException e) {
return false;

View File

@@ -89,7 +89,7 @@ public class RebaseIfNecessary extends SubmitStrategy {
.getSubmitter(n).getAccountId());
PatchSet newPatchSet =
rebaseChange.rebase(args.repo, args.rw, args.inserter,
n.getPatchsetId(), n.change(), uploader,
n.change(), n.getPatchsetId(), uploader,
mergeTip.getCurrentTip(), args.mergeUtil,
args.serverIdent.get(), false, ValidatePolicy.NONE);