Browse Source

Support aborting non-interactive rebase started from C Git

Continuing is trickier, as .git/rebase-apply contains no message file
and no git-rebase-todo.

Bug: 336820
Change-Id: I4eb87c850078ca187b38b81cc91c92afb1176945
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
stable-3.0
Robin Stocker 12 years ago committed by Matthias Sohn
parent
commit
0e9f1cf57d
  1. 24
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
  2. 150
      org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java

24
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> * Copyright (C) 2010, 2013 Mathias Kinzler <mathias.kinzler@sap.com>
* and other copyright owners as documented in the project's IP log. * and other copyright owners as documented in the project's IP log.
* *
* This program and the accompanying materials are made available * This program and the accompanying materials are made available
@ -79,6 +79,7 @@ import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason; import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.util.FileUtils;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -1506,6 +1507,27 @@ public class RebaseCommandTest extends RepositoryTestCase {
.getRepositoryState()); .getRepositoryState());
} }
@Test
public void testAbortShouldAlsoAbortNonInteractiveRebaseWithRebaseApplyDir()
throws Exception {
writeTrashFile(FILE1, "initial file");
git.add().addFilepattern(FILE1).call();
git.commit().setMessage("initial commit").call();
File applyDir = new File(db.getDirectory(), "rebase-apply");
File headName = new File(applyDir, "head-name");
FileUtils.mkdir(applyDir);
write(headName, "master");
db.writeOrigHead(db.resolve(Constants.HEAD));
git.rebase().setOperation(Operation.ABORT).call();
assertFalse("Abort should clean up .git/rebase-apply",
applyDir.exists());
assertEquals(RepositoryState.SAFE, git.getRepository()
.getRepositoryState());
}
@Test @Test
public void testRebaseShouldBeAbleToHandleEmptyLinesInRebaseTodoFile() public void testRebaseShouldBeAbleToHandleEmptyLinesInRebaseTodoFile()
throws IOException { throws IOException {

150
org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> * Copyright (C) 2010, 2013 Mathias Kinzler <mathias.kinzler@sap.com>
* and other copyright owners as documented in the project's IP log. * and other copyright owners as documented in the project's IP log.
* *
* This program and the accompanying materials are made available * This program and the accompanying materials are made available
@ -108,10 +108,15 @@ import org.eclipse.jgit.util.RawParseUtils;
*/ */
public class RebaseCommand extends GitCommand<RebaseResult> { public class RebaseCommand extends GitCommand<RebaseResult> {
/** /**
* The name of the "rebase-merge" folder * The name of the "rebase-merge" folder for interactive rebases.
*/ */
public static final String REBASE_MERGE = "rebase-merge"; //$NON-NLS-1$ public static final String REBASE_MERGE = "rebase-merge"; //$NON-NLS-1$
/**
* The name of the "rebase-apply" folder for non-interactive rebases.
*/
private static final String REBASE_APPLY = "rebase-apply"; //$NON-NLS-1$
/** /**
* The name of the "stopped-sha" file * The name of the "stopped-sha" file
*/ */
@ -177,7 +182,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
private final RevWalk walk; private final RevWalk walk;
private final File rebaseDir; private final RebaseState rebaseState;
private InteractiveHandler interactiveHandler; private InteractiveHandler interactiveHandler;
@ -187,7 +192,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
protected RebaseCommand(Repository repo) { protected RebaseCommand(Repository repo) {
super(repo); super(repo);
walk = new RevWalk(repo); walk = new RevWalk(repo);
rebaseDir = new File(repo.getDirectory(), REBASE_MERGE); rebaseState = new RebaseState(repo.getDirectory());
} }
/** /**
@ -219,9 +224,9 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
case SKIP: case SKIP:
// fall through // fall through
case CONTINUE: case CONTINUE:
String upstreamCommitId = readFile(rebaseDir, ONTO); String upstreamCommitId = rebaseState.readFile(ONTO);
try { try {
upstreamCommitName = readFile(rebaseDir, ONTO_NAME); upstreamCommitName = rebaseState.readFile(ONTO_NAME);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// Fall back to commit ID if file doesn't exist (e.g. rebase // Fall back to commit ID if file doesn't exist (e.g. rebase
// was started by C Git) // was started by C Git)
@ -242,7 +247,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
if (operation == Operation.CONTINUE) { if (operation == Operation.CONTINUE) {
newHead = continueRebase(); newHead = continueRebase();
File amendFile = new File(rebaseDir, AMEND); File amendFile = rebaseState.getFile(AMEND);
boolean amendExists = amendFile.exists(); boolean amendExists = amendFile.exists();
if (amendExists) { if (amendExists) {
FileUtils.delete(amendFile); FileUtils.delete(amendFile);
@ -265,9 +270,9 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
List<Step> steps = loadSteps(); List<Step> steps = loadSteps();
if (isInteractive()) { if (isInteractive()) {
interactiveHandler.prepareSteps(steps); interactiveHandler.prepareSteps(steps);
BufferedWriter fw = new BufferedWriter( BufferedWriter fw = new BufferedWriter(new OutputStreamWriter(
new OutputStreamWriter(new FileOutputStream(new File( new FileOutputStream(
rebaseDir, GIT_REBASE_TODO)), rebaseState.getFile(GIT_REBASE_TODO)),
Constants.CHARACTER_ENCODING)); Constants.CHARACTER_ENCODING));
fw.newLine(); fw.newLine();
try { try {
@ -339,7 +344,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
.setAmend(true).call(); .setAmend(true).call();
continue; continue;
case EDIT: case EDIT:
createFile(rebaseDir, AMEND, commitToPick.name()); rebaseState.createFile(AMEND, commitToPick.name());
return stop(commitToPick); return stop(commitToPick);
} }
} finally { } finally {
@ -347,9 +352,9 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
} }
} }
if (newHead != null) { if (newHead != null) {
String headName = readFile(rebaseDir, HEAD_NAME); String headName = rebaseState.readFile(HEAD_NAME);
updateHead(headName, newHead); updateHead(headName, newHead);
FileUtils.delete(rebaseDir, FileUtils.RECURSIVE); FileUtils.delete(rebaseState.getDir(), FileUtils.RECURSIVE);
if (lastStepWasForward) if (lastStepWasForward)
return RebaseResult.FAST_FORWARD_RESULT; return RebaseResult.FAST_FORWARD_RESULT;
return RebaseResult.OK_RESULT; return RebaseResult.OK_RESULT;
@ -458,7 +463,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
if (needsCommit) { if (needsCommit) {
CommitCommand commit = new Git(repo).commit(); CommitCommand commit = new Git(repo).commit();
commit.setMessage(readFile(rebaseDir, MESSAGE)); commit.setMessage(rebaseState.readFile(MESSAGE));
commit.setAuthor(parseAuthor()); commit.setAuthor(parseAuthor());
return commit.call(); return commit.call();
} }
@ -466,7 +471,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
} }
private PersonIdent parseAuthor() throws IOException { private PersonIdent parseAuthor() throws IOException {
File authorScriptFile = new File(rebaseDir, AUTHOR_SCRIPT); File authorScriptFile = rebaseState.getFile(AUTHOR_SCRIPT);
byte[] raw; byte[] raw;
try { try {
raw = IO.readFully(authorScriptFile); raw = IO.readFully(authorScriptFile);
@ -479,15 +484,17 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
private RebaseResult stop(RevCommit commitToPick) throws IOException { private RebaseResult stop(RevCommit commitToPick) throws IOException {
PersonIdent author = commitToPick.getAuthorIdent(); PersonIdent author = commitToPick.getAuthorIdent();
String authorScript = toAuthorScript(author); String authorScript = toAuthorScript(author);
createFile(rebaseDir, AUTHOR_SCRIPT, authorScript); rebaseState.createFile(AUTHOR_SCRIPT, authorScript);
createFile(rebaseDir, MESSAGE, commitToPick.getFullMessage()); rebaseState.createFile(MESSAGE, commitToPick.getFullMessage());
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DiffFormatter df = new DiffFormatter(bos); DiffFormatter df = new DiffFormatter(bos);
df.setRepository(repo); df.setRepository(repo);
df.format(commitToPick.getParent(0), commitToPick); df.format(commitToPick.getParent(0), commitToPick);
createFile(rebaseDir, PATCH, new String(bos.toByteArray(), rebaseState.createFile(PATCH, new String(bos.toByteArray(),
Constants.CHARACTER_ENCODING)); Constants.CHARACTER_ENCODING));
createFile(rebaseDir, STOPPED_SHA, repo.newObjectReader().abbreviate( rebaseState.createFile(STOPPED_SHA,
repo.newObjectReader()
.abbreviate(
commitToPick).name()); commitToPick).name());
// Remove cherry pick state file created by CherryPickCommand, it's not // Remove cherry pick state file created by CherryPickCommand, it's not
// needed for rebase // needed for rebase
@ -531,8 +538,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
return; return;
List<String> todoLines = new ArrayList<String>(); List<String> todoLines = new ArrayList<String>();
List<String> poppedLines = new ArrayList<String>(); List<String> poppedLines = new ArrayList<String>();
File todoFile = new File(rebaseDir, GIT_REBASE_TODO); File todoFile = rebaseState.getFile(GIT_REBASE_TODO);
File doneFile = new File(rebaseDir, DONE); File doneFile = rebaseState.getFile(DONE);
BufferedReader br = new BufferedReader(new InputStreamReader( BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(todoFile), Constants.CHARACTER_ENCODING)); new FileInputStream(todoFile), Constants.CHARACTER_ENCODING));
try { try {
@ -646,16 +653,16 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
Collections.reverse(cherryPickList); Collections.reverse(cherryPickList);
// create the folder for the meta information // create the folder for the meta information
FileUtils.mkdir(rebaseDir); FileUtils.mkdir(rebaseState.getDir());
repo.writeOrigHead(headId); repo.writeOrigHead(headId);
createFile(rebaseDir, REBASE_HEAD, headId.name()); rebaseState.createFile(REBASE_HEAD, headId.name());
createFile(rebaseDir, HEAD_NAME, headName); rebaseState.createFile(HEAD_NAME, headName);
createFile(rebaseDir, ONTO, upstreamCommit.name()); rebaseState.createFile(ONTO, upstreamCommit.name());
createFile(rebaseDir, ONTO_NAME, upstreamCommitName); rebaseState.createFile(ONTO_NAME, upstreamCommitName);
createFile(rebaseDir, INTERACTIVE, ""); //$NON-NLS-1$ rebaseState.createFile(INTERACTIVE, ""); //$NON-NLS-1$
BufferedWriter fw = new BufferedWriter(new OutputStreamWriter( BufferedWriter fw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(new File(rebaseDir, GIT_REBASE_TODO)), new FileOutputStream(rebaseState.getFile(GIT_REBASE_TODO)),
Constants.CHARACTER_ENCODING)); Constants.CHARACTER_ENCODING));
fw.write("# Created by EGit: rebasing " + upstreamCommit.name() fw.write("# Created by EGit: rebasing " + upstreamCommit.name()
+ " onto " + headId.name()); + " onto " + headId.name());
@ -687,7 +694,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
checkoutOk = checkoutCommit(upstreamCommit); checkoutOk = checkoutCommit(upstreamCommit);
} finally { } finally {
if (!checkoutOk) if (!checkoutOk)
FileUtils.delete(rebaseDir, FileUtils.RECURSIVE); FileUtils.delete(rebaseState.getDir(), FileUtils.RECURSIVE);
} }
monitor.endTask(); monitor.endTask();
@ -799,18 +806,6 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
} }
} }
private void createFile(File parentDir, String name, String content)
throws IOException {
File file = new File(parentDir, name);
FileOutputStream fos = new FileOutputStream(file);
try {
fos.write(content.getBytes(Constants.CHARACTER_ENCODING));
fos.write('\n');
} finally {
fos.close();
}
}
private RebaseResult abort(RebaseResult result) throws IOException { private RebaseResult abort(RebaseResult result) throws IOException {
try { try {
ObjectId origHead = repo.readOrigHead(); ObjectId origHead = repo.readOrigHead();
@ -840,7 +835,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
monitor.endTask(); monitor.endTask();
} }
try { try {
String headName = readFile(rebaseDir, HEAD_NAME); String headName = rebaseState.readFile(HEAD_NAME);
if (headName.startsWith(Constants.R_REFS)) { if (headName.startsWith(Constants.R_REFS)) {
monitor.beginTask(MessageFormat.format( monitor.beginTask(MessageFormat.format(
JGitText.get().resettingHead, headName), JGitText.get().resettingHead, headName),
@ -860,7 +855,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
} }
} }
// cleanup the files // cleanup the files
FileUtils.delete(rebaseDir, FileUtils.RECURSIVE); FileUtils.delete(rebaseState.getDir(), FileUtils.RECURSIVE);
repo.writeCherryPickHead(null); repo.writeCherryPickHead(null);
return result; return result;
@ -869,15 +864,6 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
} }
} }
private String readFile(File directory, String fileName) throws IOException {
byte[] content = IO.readFully(new File(directory, fileName));
// strip off the last LF
int end = content.length;
while (0 < end && content[end - 1] == '\n')
end--;
return RawParseUtils.decode(content, 0, end);
}
private boolean checkoutCommit(RevCommit commit) throws IOException, private boolean checkoutCommit(RevCommit commit) throws IOException,
CheckoutConflictException { CheckoutConflictException {
try { try {
@ -911,7 +897,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
} }
List<Step> loadSteps() throws IOException { List<Step> loadSteps() throws IOException {
byte[] buf = IO.readFully(new File(rebaseDir, GIT_REBASE_TODO)); byte[] buf = IO.readFully(rebaseState.getFile(GIT_REBASE_TODO));
int ptr = 0; int ptr = 0;
int tokenBegin = 0; int tokenBegin = 0;
ArrayList<Step> r = new ArrayList<Step>(); ArrayList<Step> r = new ArrayList<Step>();
@ -1225,4 +1211,62 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
return new PersonIdent(name, email, when, tz); return new PersonIdent(name, email, when, tz);
return null; return null;
} }
private static class RebaseState {
private final File repoDirectory;
private File dir;
public RebaseState(File repoDirectory) {
this.repoDirectory = repoDirectory;
}
public File getDir() {
if (dir == null) {
File rebaseApply = new File(repoDirectory, REBASE_APPLY);
if (rebaseApply.exists()) {
dir = rebaseApply;
} else {
File rebaseMerge = new File(repoDirectory, REBASE_MERGE);
dir = rebaseMerge;
}
}
return dir;
}
public String readFile(String name) throws IOException {
return readFile(getDir(), name);
}
public void createFile(String name, String content) throws IOException {
createFile(getDir(), name, content);
}
public File getFile(String name) {
return new File(getDir(), name);
}
private static String readFile(File directory, String fileName)
throws IOException {
byte[] content = IO.readFully(new File(directory, fileName));
// strip off the last LF
int end = content.length;
while (0 < end && content[end - 1] == '\n')
end--;
return RawParseUtils.decode(content, 0, end);
}
private static void createFile(File parentDir, String name,
String content)
throws IOException {
File file = new File(parentDir, name);
FileOutputStream fos = new FileOutputStream(file);
try {
fos.write(content.getBytes(Constants.CHARACTER_ENCODING));
fos.write('\n');
} finally {
fos.close();
}
}
}
} }

Loading…
Cancel
Save