From 8a2e221096f38ef0ab3d2e75d8ac81ad189695b0 Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Mon, 4 Mar 2019 00:07:40 +0100 Subject: [PATCH] Make pull --rebase on an unborn branch do a checkout A merging pull on an unborn branch was already supported. But a rebasing pull failed. If the user has pull.rebase = true in his user config, the pull would try to rebase. Rebasing needs a parent commit, though. Native git handles this case: git init git remote add origin git pull --rebase origin master Check up front in PullCommand for the unborn head and just do a checkout in this case. MergeCommand already has similar code. Bug: 544965 Change-Id: I1277e1ac0b0364b4623fd791f3d6b07bd5f58fca Signed-off-by: Thomas Wolf --- .../eclipse/jgit/api/CloneCommandTest.java | 28 ++++++++++++ .../src/org/eclipse/jgit/api/PullCommand.java | 45 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java index 1523b49ec..74d13883e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java @@ -718,6 +718,34 @@ public class CloneCommandTest extends RepositoryTestCase { } + @Test + public void testCloneWithPullMerge() throws Exception { + File directory = createTempDirectory("testCloneRepository1"); + try (Git g = Git.init().setDirectory(directory).setBare(false).call()) { + g.remoteAdd().setName(Constants.DEFAULT_REMOTE_NAME) + .setUri(new URIish(fileUri())).call(); + PullResult result = g.pull().setRebase(false).call(); + assertTrue(result.isSuccessful()); + assertEquals("refs/heads/master", + g.getRepository().getFullBranch()); + checkFile(new File(directory, "Test.txt"), "Hello world"); + } + } + + @Test + public void testCloneWithPullRebase() throws Exception { + File directory = createTempDirectory("testCloneRepository1"); + try (Git g = Git.init().setDirectory(directory).setBare(false).call()) { + g.remoteAdd().setName(Constants.DEFAULT_REMOTE_NAME) + .setUri(new URIish(fileUri())).call(); + PullResult result = g.pull().setRebase(true).call(); + assertTrue(result.isSuccessful()); + assertEquals("refs/heads/master", + g.getRepository().getFullBranch()); + checkFile(new File(directory, "Test.txt"), "Hello world"); + } + } + private String fileUri() { return "file://" + git.getRepository().getWorkTree().getAbsolutePath(); } 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 f0ad29db4..bdb2d1bbc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java @@ -60,6 +60,7 @@ import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.api.errors.RefNotAdvertisedException; import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; +import org.eclipse.jgit.dircache.DirCacheCheckout; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode; @@ -67,12 +68,17 @@ import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefUpdate.Result; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode; import org.eclipse.jgit.merge.MergeStrategy; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.transport.TagOpt; @@ -339,6 +345,45 @@ public class PullCommand extends TransportCommand { PullResult result; if (pullRebaseMode != BranchRebaseMode.NONE) { + try { + Ref head = repo.exactRef(Constants.HEAD); + if (head == null) { + throw new NoHeadException(JGitText + .get().commitOnRepoWithoutHEADCurrentlyNotSupported); + } + ObjectId headId = head.getObjectId(); + if (headId == null) { + // Pull on an unborn branch: checkout + try (RevWalk revWalk = new RevWalk(repo)) { + RevCommit srcCommit = revWalk + .parseCommit(commitToMerge); + DirCacheCheckout dco = new DirCacheCheckout(repo, + repo.lockDirCache(), srcCommit.getTree()); + dco.setFailOnConflict(true); + dco.setProgressMonitor(monitor); + dco.checkout(); + RefUpdate refUpdate = repo + .updateRef(head.getTarget().getName()); + refUpdate.setNewObjectId(commitToMerge); + refUpdate.setExpectedOldObjectId(null); + refUpdate.setRefLogMessage("initial pull", false); //$NON-NLS-1$ + if (refUpdate.update() != Result.NEW) { + throw new NoHeadException(JGitText + .get().commitOnRepoWithoutHEADCurrentlyNotSupported); + } + monitor.endTask(); + return new PullResult(fetchRes, remote, + RebaseResult.result( + RebaseResult.Status.FAST_FORWARD, + srcCommit)); + } + } + } catch (NoHeadException e) { + throw e; + } catch (IOException e) { + throw new JGitInternalException(JGitText + .get().exceptionCaughtDuringExecutionOfPullCommand, e); + } RebaseCommand rebase = new RebaseCommand(repo); RebaseResult rebaseRes = rebase.setUpstream(commitToMerge) .setUpstreamName(upstreamName).setProgressMonitor(monitor)