* @throws NoHeadException
* @throws RefNotFoundException
*/
public RebaseResult call() throws GitAPIException, NoHeadException,
RefNotFoundException, WrongRepositoryStateException {
RevCommit newHead = null;
boolean lastStepWasForward = false;
checkCallable();
checkParameters();
try {
switch (operation) {
case ABORT:
try {
return abort(RebaseResult.ABORTED_RESULT);
} catch (IOException ioe) {
throw new JGitInternalException(ioe.getMessage(), ioe);
}
case SKIP:
// fall through
case CONTINUE:
String upstreamCommitId = readFile(rebaseDir, ONTO);
try {
upstreamCommitName = readFile(rebaseDir, ONTO_NAME);
} catch (FileNotFoundException e) {
// Fall back to commit ID if file doesn't exist (e.g. rebase
// was started by C Git)
upstreamCommitName = upstreamCommitId;
}
this.upstreamCommit = walk.parseCommit(repo
.resolve(upstreamCommitId));
break;
case BEGIN:
RebaseResult res = initFilesAndRewind();
if (res != null)
return res;
}
if (monitor.isCancelled())
return abort(RebaseResult.ABORTED_RESULT);
if (operation == Operation.CONTINUE) {
newHead = continueRebase();
File amendFile = new File(rebaseDir, AMEND);
boolean amendExists = amendFile.exists();
if (amendExists) {
FileUtils.delete(amendFile);
}
if (newHead == null && !amendExists) {
// continueRebase() returns null only if no commit was
// neccessary. This means that no changes where left over
// after resolving all conflicts. In this case, cgit stops
// and displays a nice message to the user, telling him to
// either do changes or skip the commit instead of continue.
return RebaseResult.NOTHING_TO_COMMIT_RESULT;
}
}
if (operation == Operation.SKIP)
newHead = checkoutCurrentHead();
ObjectReader or = repo.newObjectReader();
List<Step> steps = loadSteps();
if (isInteractive()) {
interactiveHandler.prepareSteps(steps);
BufferedWriter fw = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(new File(
rebaseDir, GIT_REBASE_TODO)),
Constants.CHARACTER_ENCODING));
fw.newLine();
try {
StringBuilder sb = new StringBuilder();
for (Step step : steps) {
sb.setLength(0);
sb.append(step.action.token);
sb.append(" ");
sb.append(step.commit.name());
sb.append(" ");
sb.append(RawParseUtils.decode(step.shortMessage)
.trim());
fw.write(sb.toString());
fw.newLine();
}
} finally {
fw.close();
}
}
for (Step step : steps) {
popSteps(1);
Collection<ObjectId> ids = or.resolve(step.commit);
if (ids.size() != 1)
throw new JGitInternalException(
"Could not resolve uniquely the abbreviated object ID");
RevCommit commitToPick = walk
.parseCommit(ids.iterator().next());
if (monitor.isCancelled())
return new RebaseResult(commitToPick);
try {
monitor.beginTask(MessageFormat.format(
JGitText.get().applyingCommit,
commitToPick.getShortMessage()),
ProgressMonitor.UNKNOWN);
// if the first parent of commitToPick is the current HEAD,
// we do a fast-forward instead of cherry-pick to avoid
// unnecessary object rewriting
newHead = tryFastForward(commitToPick);
lastStepWasForward = newHead != null;
if (!lastStepWasForward) {
// TODO if the content of this commit is already merged
// here we should skip this step in order to avoid
// confusing pseudo-changed
String ourCommitName = getOurCommitName();
CherryPickResult cherryPickResult = new Git(repo)
.cherryPick().include(commitToPick)
.setOurCommitName(ourCommitName).call();
switch (cherryPickResult.getStatus()) {
case FAILED:
if (operation == Operation.BEGIN)
return abort(new RebaseResult(
cherryPickResult.getFailingPaths()));
else
return stop(commitToPick);
case CONFLICTING:
return stop(commitToPick);
case OK:
newHead = cherryPickResult.getNewHead();
}
}
switch (step.action) {
case PICK:
continue; // continue rebase process on pick command
case REWORD:
String oldMessage = commitToPick.getFullMessage();
String newMessage = interactiveHandler
.modifyCommitMessage(oldMessage);
newHead = new Git(repo).commit().setMessage(newMessage)
.setAmend(true).call();
continue;
case EDIT:
createFile(rebaseDir, AMEND, commitToPick.name());
return stop(commitToPick);
}
} finally {
monitor.endTask();
}