Support pull on detached HEAD

Bug: 485396
Change-Id: I82be09385c9b0bcc0054fea5a9cb9d178a41e278
Signed-off-by: Mickael Istria <mistria@redhat.com>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
Mickael Istria 2017-03-14 17:41:55 +01:00 committed by Matthias Sohn
parent 8f7d0a4fbe
commit 5b84e25fa3
2 changed files with 76 additions and 23 deletions

View File

@ -61,6 +61,7 @@
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.lib.StoredConfig;
@ -147,6 +148,57 @@ public void testPullFastForwardWithBranchInSource() throws Exception {
}
@Test
public void testPullFastForwardDetachedHead() throws Exception {
Repository repository = source.getRepository();
writeToFile(sourceFile, "2nd commit");
source.add().addFilepattern("SomeFile.txt").call();
source.commit().setMessage("2nd commit").call();
try (RevWalk revWalk = new RevWalk(repository)) {
// git checkout HEAD^
String initialBranch = repository.getBranch();
Ref initialRef = repository.findRef(Constants.HEAD);
RevCommit initialCommit = revWalk
.parseCommit(initialRef.getObjectId());
assertEquals("this test need linear history", 1,
initialCommit.getParentCount());
source.checkout().setName(initialCommit.getParent(0).getName())
.call();
assertFalse("expected detached HEAD",
repository.getFullBranch().startsWith(Constants.R_HEADS));
// change and commit another file
File otherFile = new File(sourceFile.getParentFile(),
System.currentTimeMillis() + ".tst");
writeToFile(otherFile, "other 2nd commit");
source.add().addFilepattern(otherFile.getName()).call();
RevCommit newCommit = source.commit().setMessage("other 2nd commit")
.call();
// git pull --rebase initialBranch
source.pull().setRebase(true).setRemote(".")
.setRemoteBranchName(initialBranch)
.call();
assertEquals(RepositoryState.SAFE,
source.getRepository().getRepositoryState());
Ref head = source.getRepository().findRef(Constants.HEAD);
RevCommit headCommit = revWalk.parseCommit(head.getObjectId());
// HEAD^ == initialCommit, no merge commit
assertEquals(1, headCommit.getParentCount());
assertEquals(initialCommit, headCommit.getParent(0));
// both contributions for both commits are available
assertFileContentsEqual(sourceFile, "2nd commit");
assertFileContentsEqual(otherFile, "other 2nd commit");
// HEAD has same message as rebased commit
assertEquals(newCommit.getShortMessage(),
headCommit.getShortMessage());
}
}
@Test
public void testPullConflict() throws Exception {
PullResult res = target.pull().call();

View File

@ -203,62 +203,63 @@ public PullCommand setRebase(BranchRebaseMode rebaseMode) {
@Override
public PullResult call() throws GitAPIException,
WrongRepositoryStateException, InvalidConfigurationException,
DetachedHeadException, InvalidRemoteException, CanceledException,
InvalidRemoteException, CanceledException,
RefNotFoundException, RefNotAdvertisedException, NoHeadException,
org.eclipse.jgit.api.errors.TransportException {
checkCallable();
monitor.beginTask(JGitText.get().pullTaskName, 2);
Config repoConfig = repo.getConfig();
String branchName;
String branchName = null;
try {
String fullBranch = repo.getFullBranch();
if (fullBranch == null)
throw new NoHeadException(
JGitText.get().pullOnRepoWithoutHEADCurrentlyNotSupported);
if (!fullBranch.startsWith(Constants.R_HEADS)) {
// we can not pull if HEAD is detached and branch is not
// specified explicitly
throw new DetachedHeadException();
if (fullBranch != null
&& fullBranch.startsWith(Constants.R_HEADS)) {
branchName = fullBranch.substring(Constants.R_HEADS.length());
}
branchName = fullBranch.substring(Constants.R_HEADS.length());
} catch (IOException e) {
throw new JGitInternalException(
JGitText.get().exceptionCaughtDuringExecutionOfPullCommand,
e);
}
if (remoteBranchName == null && branchName != null) {
// get the name of the branch in the remote repository
// stored in configuration key branch.<branch name>.merge
remoteBranchName = repoConfig.getString(
ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
ConfigConstants.CONFIG_KEY_MERGE);
}
if (remoteBranchName == null) {
remoteBranchName = branchName;
}
if (remoteBranchName == null) {
throw new NoHeadException(
JGitText.get().cannotCheckoutFromUnbornBranch);
}
if (!repo.getRepositoryState().equals(RepositoryState.SAFE))
throw new WrongRepositoryStateException(MessageFormat.format(
JGitText.get().cannotPullOnARepoWithState, repo
.getRepositoryState().name()));
Config repoConfig = repo.getConfig();
if (remote == null) {
if (remote == null && branchName != null) {
// get the configured remote for the currently checked out branch
// stored in configuration key branch.<branch name>.remote
remote = repoConfig.getString(
ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
ConfigConstants.CONFIG_KEY_REMOTE);
}
if (remote == null)
if (remote == null) {
// fall back to default remote
remote = Constants.DEFAULT_REMOTE_NAME;
if (remoteBranchName == null)
// get the name of the branch in the remote repository
// stored in configuration key branch.<branch name>.merge
remoteBranchName = repoConfig.getString(
ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
ConfigConstants.CONFIG_KEY_MERGE);
}
// determines whether rebase should be used after fetching
if (pullRebaseMode == null) {
if (pullRebaseMode == null && branchName != null) {
pullRebaseMode = getRebaseMode(branchName, repoConfig);
}
if (remoteBranchName == null)
remoteBranchName = branchName;
final boolean isRemote = !remote.equals("."); //$NON-NLS-1$
String remoteUri;