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 <mathias.kinzler@sap.com>
This commit is contained in:
Mathias Kinzler 2010-10-19 08:54:28 +02:00 committed by Shawn O. Pearce
parent 0544c9af41
commit 7668a46282
4 changed files with 91 additions and 33 deletions

View File

@ -48,7 +48,9 @@
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 void testPullConflict() throws Exception {
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();

View File

@ -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

View File

@ -173,6 +173,7 @@ public static JGitText get() {
/***/ public String couldNotCheckOutBecauseOfConflicts;
/***/ public String couldNotDeleteLockFileShouldNotHappen;
/***/ public String couldNotDeleteTemporaryIndexFileShouldNotHappen;
/***/ public String couldNotGetAdvertisedRef;
/***/ public String couldNotLockHEAD;
/***/ public String couldNotReadIndexInOneGo;
/***/ public String couldNotRenameDeleteOldIndex;

View File

@ -157,14 +157,6 @@ public PullResult call() throws WrongRepositoryStateException,
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.<branch name>.merge
@ -175,13 +167,14 @@ public PullResult call() throws WrongRepositoryStateException,
// 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 PullResult call() throws WrongRepositoryStateException,
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(