From 7668a462829b12e4f6a192c43157152ef63ff305 Mon Sep 17 00:00:00 2001 From: Mathias Kinzler Date: Tue, 19 Oct 2010 08:54:28 +0200 Subject: [PATCH] PullCommand: support upstream configuration for local branches When creating a local branch based on another local branch, the upstream configuration contains "." as origin and the source branch as "merge". The PullCommand should support this by skipping the fetch step altogether and use the base branch to merge with. Change-Id: I260a1771aeeffca5b0161d1494fd63c672ecc2a6 Signed-off-by: Mathias Kinzler --- .../org/eclipse/jgit/api/PullCommandTest.java | 42 ++++++++++ .../org/eclipse/jgit/JGitText.properties | 1 + .../src/org/eclipse/jgit/JGitText.java | 1 + .../src/org/eclipse/jgit/api/PullCommand.java | 80 +++++++++++-------- 4 files changed, 91 insertions(+), 33 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java index de75fd5b6..48ede966f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java @@ -48,7 +48,9 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; import org.eclipse.jgit.api.MergeResult.MergeStatus; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RepositoryTestCase; import org.eclipse.jgit.lib.StoredConfig; @@ -125,6 +127,46 @@ public class PullCommandTest extends RepositoryTestCase { assertFileContentsEqual(targetFile, result); } + public void testPullLocalConflict() throws Exception { + target.branchCreate().setName("basedOnMaster").setStartPoint( + "refs/heads/master").setUpstreamMode(SetupUpstreamMode.TRACK) + .call(); + target.getRepository().updateRef(Constants.HEAD).link( + "refs/heads/basedOnMaster"); + PullResult res = target.pull().call(); + // nothing to update since we don't have different data yet + assertNull(res.getFetchResult()); + assertTrue(res.getMergeResult().getMergeStatus().equals( + MergeStatus.ALREADY_UP_TO_DATE)); + + assertFileContentsEqual(targetFile, "Hello world"); + + // change the file in master + target.getRepository().updateRef(Constants.HEAD).link( + "refs/heads/master"); + writeToFile(targetFile, "Master change"); + target.add().addFilepattern("SomeFile.txt").call(); + target.commit().setMessage("Source change in master").call(); + + // change the file in slave + target.getRepository().updateRef(Constants.HEAD).link( + "refs/heads/basedOnMaster"); + writeToFile(targetFile, "Slave change"); + target.add().addFilepattern("SomeFile.txt").call(); + target.commit().setMessage("Source change in based on master").call(); + + res = target.pull().call(); + + String sourceChangeString = "Master change\n>>>>>>> branch 'refs/heads/master' of local repository"; + + assertNull(res.getFetchResult()); + assertEquals(res.getMergeResult().getMergeStatus(), + MergeStatus.CONFLICTING); + String result = "<<<<<<< HEAD\nSlave change\n=======\n" + + sourceChangeString + "\n"; + assertFileContentsEqual(targetFile, result); + } + @Override protected void setUp() throws Exception { super.setUp(); diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties index 409b43492..8af6e315f 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties @@ -113,6 +113,7 @@ corruptionDetectedReReadingAt=Corruption detected re-reading at {0} couldNotCheckOutBecauseOfConflicts=Could not check out because of conflicts couldNotDeleteLockFileShouldNotHappen=Could not delete lock file. Should not happen couldNotDeleteTemporaryIndexFileShouldNotHappen=Could not delete temporary index file. Should not happen +couldNotGetAdvertisedRef=Could not get advertised Ref for branch {0} couldNotLockHEAD=Could not lock HEAD couldNotReadIndexInOneGo=Could not read index in one go, only {0} out of {1} read couldNotRenameDeleteOldIndex=Could not rename delete old index diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java index d6c601800..6a75a9eb8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java @@ -173,6 +173,7 @@ public class JGitText extends TranslationBundle { /***/ public String couldNotCheckOutBecauseOfConflicts; /***/ public String couldNotDeleteLockFileShouldNotHappen; /***/ public String couldNotDeleteTemporaryIndexFileShouldNotHappen; + /***/ public String couldNotGetAdvertisedRef; /***/ public String couldNotLockHEAD; /***/ public String couldNotReadIndexInOneGo; /***/ public String couldNotRenameDeleteOldIndex; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java index b7f09d9a7..acbf3f10a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java @@ -157,14 +157,6 @@ public class PullCommand extends GitCommand { throw new InvalidConfigurationException(MessageFormat.format( JGitText.get().missingConfigurationForKey, missingKey)); } - final String remoteUri = repo.getConfig().getString("remote", remote, - ConfigConstants.CONFIG_KEY_URL); - if (remoteUri == null) { - String missingKey = ConfigConstants.CONFIG_REMOTE_SECTION + DOT - + remote + DOT + ConfigConstants.CONFIG_KEY_URL; - throw new InvalidConfigurationException(MessageFormat.format( - JGitText.get().missingConfigurationForKey, missingKey)); - } // get the name of the branch in the remote repository // stored in configuration key branch..merge @@ -175,13 +167,14 @@ public class PullCommand extends GitCommand { // check if the branch is configured for pull-rebase remoteBranchName = repoConfig.getString( ConfigConstants.CONFIG_BRANCH_SECTION, branchName, - ConfigConstants.CONFIG_KEY_MERGE); + ConfigConstants.CONFIG_KEY_REBASE); if (remoteBranchName != null) { // TODO implement pull-rebase throw new JGitInternalException( "Pull with rebase is not yet supported"); } } + if (remoteBranchName == null) { String missingKey = ConfigConstants.CONFIG_BRANCH_SECTION + DOT + branchName + DOT + ConfigConstants.CONFIG_KEY_MERGE; @@ -189,45 +182,66 @@ public class PullCommand extends GitCommand { JGitText.get().missingConfigurationForKey, missingKey)); } - if (monitor.isCancelled()) - throw new CanceledException(MessageFormat.format( - JGitText.get().operationCanceled, - JGitText.get().pullTaskName)); + final boolean isRemote = !remote.equals("."); + String remoteUri; + FetchResult fetchRes; + if (isRemote) { + remoteUri = repo.getConfig().getString("remote", remote, + ConfigConstants.CONFIG_KEY_URL); + if (remoteUri == null) { + String missingKey = ConfigConstants.CONFIG_REMOTE_SECTION + DOT + + remote + DOT + ConfigConstants.CONFIG_KEY_URL; + throw new InvalidConfigurationException(MessageFormat.format( + JGitText.get().missingConfigurationForKey, missingKey)); + } - FetchCommand fetch = new FetchCommand(repo); - fetch.setRemote(remote); - if (monitor != null) - fetch.setProgressMonitor(monitor); - fetch.setTimeout(this.timeout); + if (monitor.isCancelled()) + throw new CanceledException(MessageFormat.format( + JGitText.get().operationCanceled, + JGitText.get().pullTaskName)); - FetchResult fetchRes = fetch.call(); + FetchCommand fetch = new FetchCommand(repo); + fetch.setRemote(remote); + if (monitor != null) + fetch.setProgressMonitor(monitor); + fetch.setTimeout(this.timeout); + + fetchRes = fetch.call(); + } else { + // we can skip the fetch altogether + remoteUri = "local repository"; + fetchRes = null; + } monitor.update(1); // we check the updates to see which of the updated branches corresponds // to the remote branch name - AnyObjectId commitToMerge = null; + AnyObjectId commitToMerge; - Ref r = fetchRes.getAdvertisedRef(remoteBranchName); - if (r == null) - r = fetchRes.getAdvertisedRef(Constants.R_HEADS + remoteBranchName); - if (r == null) { - // TODO: we should be able to get the mapping also if nothing was - // updated by the fetch; for the time being, use the naming - // convention as fall back - String remoteTrackingBranch = Constants.R_REMOTES + remote + '/' - + branchName; + if (isRemote) { + Ref r = null; + if (fetchRes != null) { + r = fetchRes.getAdvertisedRef(remoteBranchName); + if (r == null) + r = fetchRes.getAdvertisedRef(Constants.R_HEADS + + remoteBranchName); + } + if (r == null) + throw new JGitInternalException(MessageFormat.format(JGitText + .get().couldNotGetAdvertisedRef, remoteBranchName)); + else + commitToMerge = r.getObjectId(); + } else { try { - commitToMerge = repo.resolve(remoteTrackingBranch); + commitToMerge = repo.resolve(remoteBranchName); } catch (IOException e) { throw new JGitInternalException( JGitText.get().exceptionCaughtDuringExecutionOfPullCommand, e); } - - } else - commitToMerge = r.getObjectId(); + } if (monitor.isCancelled()) throw new CanceledException(MessageFormat.format(