summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Aniszczyk <caniszczyk@gmail.com>2011-05-18 11:39:33 -0500
committerChris Aniszczyk <caniszczyk@gmail.com>2011-05-18 11:40:21 -0500
commit557ea857e3b5229379476f1ee4160fcf5b695bbd (patch)
treebdfe51118576afbc4cc1cf2cd129e1d89f6b034b
parent7449b9a297af193107560c42508c53d7adb00226 (diff)
downloadjgit-557ea857e3b5229379476f1ee4160fcf5b695bbd.tar.gz
jgit-557ea857e3b5229379476f1ee4160fcf5b695bbd.zip
Implement rebase ff for upstream branches with merge commits
Change Ib9898fe0f982fa08e41f1dca9452c43de715fdb6 added support for the 'cherry-pick' fast forward case where the upstream commit history does not include any merge commits. This change adds support for the case where merge commits exist and the local branch has no changes. Bug: 344779 Change-Id: If203ce5aa1b4e5d4d7982deb621b710e71f4ee10 Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java111
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java6
2 files changed, 64 insertions, 53 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
index 7e2e677993..114ef03a3b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -199,7 +199,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
switch (operation) {
case ABORT:
try {
- return abort(new RebaseResult(Status.ABORTED));
+ return abort(RebaseResult.ABORTED_RESULT);
} catch (IOException ioe) {
throw new JGitInternalException(ioe.getMessage(), ioe);
}
@@ -217,7 +217,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
}
if (monitor.isCancelled())
- return abort(new RebaseResult(Status.ABORTED));
+ return abort(RebaseResult.ABORTED_RESULT);
if (operation == Operation.CONTINUE)
newHead = continueRebase();
@@ -272,42 +272,48 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
}
}
if (newHead != null) {
- // point the previous head (if any) to the new commit
String headName = readFile(rebaseDir, HEAD_NAME);
- if (headName.startsWith(Constants.R_REFS)) {
- RefUpdate rup = repo.updateRef(headName);
- rup.setNewObjectId(newHead);
- Result res = rup.forceUpdate();
- switch (res) {
- case FAST_FORWARD:
- case FORCED:
- case NO_CHANGE:
- break;
- default:
- throw new JGitInternalException("Updating HEAD failed");
- }
- rup = repo.updateRef(Constants.HEAD);
- res = rup.link(headName);
- switch (res) {
- case FAST_FORWARD:
- case FORCED:
- case NO_CHANGE:
- break;
- default:
- throw new JGitInternalException("Updating HEAD failed");
- }
- }
+ updateHead(headName, newHead);
FileUtils.delete(rebaseDir, FileUtils.RECURSIVE);
if (lastStepWasForward)
- return new RebaseResult(Status.FAST_FORWARD);
- return new RebaseResult(Status.OK);
+ return RebaseResult.FAST_FORWARD_RESULT;
+ return RebaseResult.OK_RESULT;
}
- return new RebaseResult(Status.UP_TO_DATE);
+ return RebaseResult.FAST_FORWARD_RESULT;
} catch (IOException ioe) {
throw new JGitInternalException(ioe.getMessage(), ioe);
}
}
+ private void updateHead(String headName, RevCommit newHead)
+ throws IOException {
+ // point the previous head (if any) to the new commit
+
+ if (headName.startsWith(Constants.R_REFS)) {
+ RefUpdate rup = repo.updateRef(headName);
+ rup.setNewObjectId(newHead);
+ Result res = rup.forceUpdate();
+ switch (res) {
+ case FAST_FORWARD:
+ case FORCED:
+ case NO_CHANGE:
+ break;
+ default:
+ throw new JGitInternalException("Updating HEAD failed");
+ }
+ rup = repo.updateRef(Constants.HEAD);
+ res = rup.link(headName);
+ switch (res) {
+ case FAST_FORWARD:
+ case FORCED:
+ case NO_CHANGE:
+ break;
+ default:
+ throw new JGitInternalException("Updating HEAD failed");
+ }
+ }
+ }
+
private RevCommit checkoutCurrentHead() throws IOException,
NoHeadException, JGitInternalException {
ObjectId headTree = repo.resolve(Constants.HEAD + "^{tree}");
@@ -505,9 +511,6 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
// we need to store everything into files so that we can implement
// --skip, --continue, and --abort
- // first of all, we determine the commits to be applied
- List<RevCommit> cherryPickList = new ArrayList<RevCommit>();
-
Ref head = repo.getRef(Constants.HEAD);
if (head == null || head.getObjectId() == null)
throw new RefNotFoundException(MessageFormat.format(
@@ -523,36 +526,38 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
throw new RefNotFoundException(MessageFormat.format(
JGitText.get().refNotResolved, Constants.HEAD));
RevCommit headCommit = walk.lookupCommit(headId);
+ RevCommit upstream = walk.lookupCommit(upstreamCommit.getId());
+
+ if (walk.isMergedInto(upstream, headCommit))
+ return RebaseResult.UP_TO_DATE_RESULT;
+ else if (walk.isMergedInto(headCommit, upstream)) {
+ // head is already merged into upstream, fast-foward
+ monitor.beginTask(MessageFormat.format(
+ JGitText.get().resettingHead,
+ upstreamCommit.getShortMessage()), ProgressMonitor.UNKNOWN);
+ checkoutCommit(upstreamCommit);
+ monitor.endTask();
+
+ updateHead(headName, upstreamCommit);
+ return RebaseResult.FAST_FORWARD_RESULT;
+ }
+
monitor.beginTask(JGitText.get().obtainingCommitsForCherryPick,
ProgressMonitor.UNKNOWN);
+ // determine the commits to be applied
LogCommand cmd = new Git(repo).log().addRange(upstreamCommit,
headCommit);
Iterable<RevCommit> commitsToUse = cmd.call();
+
+ List<RevCommit> cherryPickList = new ArrayList<RevCommit>();
for (RevCommit commit : commitsToUse) {
+ if (commit.getParentCount() != 1)
+ throw new JGitInternalException(
+ JGitText.get().canOnlyCherryPickCommitsWithOneParent);
cherryPickList.add(commit);
}
- // if the upstream commit is in a direct line to the current head,
- // the log command will not report any commits; in this case,
- // we create the cherry-pick list ourselves
- if (cherryPickList.isEmpty()) {
- Iterable<RevCommit> parents = new Git(repo).log().add(
- upstreamCommit).call();
- for (RevCommit parent : parents) {
- if (parent.equals(headCommit))
- break;
- if (parent.getParentCount() != 1)
- throw new JGitInternalException(
- JGitText.get().canOnlyCherryPickCommitsWithOneParent);
- cherryPickList.add(parent);
- }
- }
-
- // nothing to do: return with UP_TO_DATE_RESULT
- if (cherryPickList.isEmpty())
- return RebaseResult.UP_TO_DATE_RESULT;
-
Collections.reverse(cherryPickList);
// create the folder for the meta information
FileUtils.mkdir(rebaseDir);
@@ -586,11 +591,13 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
}
monitor.endTask();
+
// we rewind to the upstream commit
monitor.beginTask(MessageFormat.format(JGitText.get().rewinding,
upstreamCommit.getShortMessage()), ProgressMonitor.UNKNOWN);
checkoutCommit(upstreamCommit);
monitor.endTask();
+
return null;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java
index c0e339017e..af070d6535 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java
@@ -82,6 +82,10 @@ public class RebaseResult {
FAST_FORWARD;
}
+ static final RebaseResult OK_RESULT = new RebaseResult(Status.OK);
+
+ static final RebaseResult ABORTED_RESULT = new RebaseResult(Status.ABORTED);
+
static final RebaseResult UP_TO_DATE_RESULT = new RebaseResult(
Status.UP_TO_DATE);
@@ -94,7 +98,7 @@ public class RebaseResult {
private Map<String, MergeFailureReason> failingPaths;
- RebaseResult(Status status) {
+ private RebaseResult(Status status) {
this.mySatus = status;
currentCommit = null;
}