Browse Source

Add support for rebase interactive 'reword' command

'reword' command is used to change commit message of any
commit in git history.

Bug: 394575
Change-Id: Ic974e76dfd923fd6f0cb8f07d1a6fbecd9abbf31
Signed-off-by: Dariusz Luksza <dariusz@luksza.org>
Signed-off-by: Chris Aniszczyk <zx@twitter.com>
tags/v2.2.0.201212191850-r
Dariusz Luksza 11 years ago
parent
commit
84fb2b59d1

+ 58
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java View File

@@ -53,10 +53,12 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jgit.api.MergeResult.MergeStatus;
import org.eclipse.jgit.api.RebaseCommand.Action;
import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler;
import org.eclipse.jgit.api.RebaseCommand.Operation;
import org.eclipse.jgit.api.RebaseCommand.Step;
import org.eclipse.jgit.api.RebaseResult.Status;
@@ -1523,6 +1525,62 @@ public class RebaseCommandTest extends RepositoryTestCase {
assertEquals("2222222", steps.get(1).commit.name());
}

@Test
public void testParseRewordCommand() throws Exception {
String todo = "pick 1111111 Commit 1\n"
+ "reword 2222222 Commit 2\n";
write(getTodoFile(), todo);

RebaseCommand rebaseCommand = git.rebase();
List<Step> steps = rebaseCommand.loadSteps();

assertEquals(2, steps.size());
assertEquals("1111111", steps.get(0).commit.name());
assertEquals("2222222", steps.get(1).commit.name());
assertEquals(Action.REWORD, steps.get(1).action);
}

@Test
public void testRebaseInteractiveReword() throws Exception {
// create file1 on master
writeTrashFile(FILE1, FILE1);
git.add().addFilepattern(FILE1).call();
git.commit().setMessage("Add file1").call();
assertTrue(new File(db.getWorkTree(), FILE1).exists());

// create file2 on master
writeTrashFile("file2", "file2");
git.add().addFilepattern("file2").call();
git.commit().setMessage("Add file2").call();
assertTrue(new File(db.getWorkTree(), "file2").exists());

// update FILE1 on master
writeTrashFile(FILE1, "blah");
git.add().addFilepattern(FILE1).call();
git.commit().setMessage("updated file1 on master").call();

writeTrashFile("file2", "more change");
git.add().addFilepattern("file2").call();
git.commit().setMessage("update file2 on side").call();

RebaseResult res = git.rebase().setUpstream("HEAD~2")
.runInteractively(new InteractiveHandler() {
public void prepareSteps(List<Step> steps) {
steps.get(0).action = Action.REWORD;
}
public String modifyCommitMessage(String commit) {
return "rewritten commit message";
}
}).call();
assertTrue(new File(db.getWorkTree(), "file2").exists());
checkFile(new File(db.getWorkTree(), "file2"), "more change");
assertEquals(Status.OK, res.getStatus());
Iterator<RevCommit> logIterator = git.log().all().call().iterator();
logIterator.next(); // skip first commit;
String actualCommitMag = logIterator.next().getShortMessage();
assertEquals("rewritten commit message", actualCommitMag);
}

private File getTodoFile() {
File todoFile = new File(db.getDirectory(),
"rebase-merge/git-rebase-todo");

+ 129
- 7
org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java View File

@@ -177,6 +177,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> {

private final File rebaseDir;

private InteractiveHandler interactiveHandler;

/**
* @param repo
*/
@@ -254,6 +256,30 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
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(new String(step.shortMessage,
Constants.CHARACTER_ENCODING).trim());
fw.write(sb.toString());
fw.newLine();
}
} finally {
fw.close();
}
}
for (Step step : steps) {
popSteps(1);
Collection<ObjectId> ids = or.resolve(step.commit);
@@ -295,6 +321,17 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
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;
}
} finally {
monitor.endTask();
}
@@ -492,6 +529,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
String popCandidate = br.readLine();
if (popCandidate == null)
break;
if (popCandidate.length() == 0)
continue;
if (popCandidate.charAt(0) == '#')
continue;
int spaceIndex = popCandidate.indexOf(' ');
@@ -564,9 +603,9 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
RevCommit headCommit = walk.lookupCommit(headId);
RevCommit upstream = walk.lookupCommit(upstreamCommit.getId());

if (walk.isMergedInto(upstream, headCommit))
if (!isInteractive() && walk.isMergedInto(upstream, headCommit))
return RebaseResult.UP_TO_DATE_RESULT;
else if (walk.isMergedInto(headCommit, upstream)) {
else if (!isInteractive() && walk.isMergedInto(headCommit, upstream)) {
// head is already merged into upstream, fast-foward
monitor.beginTask(MessageFormat.format(
JGitText.get().resettingHead,
@@ -647,6 +686,10 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
return null;
}

private boolean isInteractive() {
return interactiveHandler != null;
}

/**
* checks if we can fast-forward and returns the new head if it is possible
*
@@ -988,15 +1031,59 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
return this;
}

static enum Action {
PICK("pick"); // later add SQUASH, EDIT, etc.
/**
* Enables interactive rebase
*
* @param handler
* @return this
*/
public RebaseCommand runInteractively(InteractiveHandler handler) {
this.interactiveHandler = handler;
return this;
}

/**
* Allows configure rebase interactive process and modify commit message
*/
public interface InteractiveHandler {
/**
* Given list of {@code steps} should be modified according to user
* rebase configuration
* @param steps
* initial configuration of rebase interactive
*/
void prepareSteps(List<Step> steps);

/**
* Used for editing commit message on REWORD
*
* @param commit
* @return new commit message
*/
String modifyCommitMessage(String commit);
}

/**
* Describes rebase actions
*/
public static enum Action {
/** Use commit */
PICK("pick", "p"),
/** Use commit, but edit the commit message */
REWORD("reword", "r"); // later add SQUASH, EDIT, etc.

private final String token;

private Action(String token) {
private final String shortToken;

private Action(String token, String shortToken) {
this.token = token;
this.shortToken = shortToken;
}

/**
* @return full action token name
*/
public String toToken() {
return this.token;
}
@@ -1007,15 +1094,20 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
}

static Action parse(String token) {
if (token.equals("pick") || token.equals("p"))
if (token.equals(PICK.token) || token.equals(PICK.shortToken))
return PICK;
if (token.equals(REWORD.token) || token.equals(REWORD.shortToken))
return REWORD;
throw new JGitInternalException(MessageFormat.format(
JGitText.get().unknownOrUnsupportedCommand, token,
PICK.toToken()));
}
}

static class Step {
/**
* Describes single rebase step
*/
public static class Step {
Action action;

AbbreviatedObjectId commit;
@@ -1026,6 +1118,36 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
this.action = action;
}

/**
* @return rebase action type
*/
public Action getAction() {
return action;
}

/**
* @param action
*/
public void setAction(Action action) {
this.action = action;
}

/**
* @return abbreviated commit SHA-1 of commit that action will be
* performed on
*/
public AbbreviatedObjectId getCommit() {
return commit;
}

/**
* @return short message commit of commit that action will be performed
* on
*/
public byte[] getShortMessage() {
return shortMessage;
}

@Override
public String toString() {
return "Step[" + action + ", "

Loading…
Cancel
Save