From 89a4dcf71ff3326aa6313b3a988b7721c3470858 Mon Sep 17 00:00:00 2001 From: Mathias Kinzler Date: Mon, 20 Dec 2010 10:35:10 +0100 Subject: [PATCH] Checkout: fix handling if name does not refer to a local branch The CheckoutCommand does not handle names other than local branch names properly; it must detach HEAD if such a name is encountered (for example a commit ID or a remote tracking branch). Change-Id: I5d55177f4029bcc34fc2649fd564b125a2929cc4 Signed-off-by: Mathias Kinzler Signed-off-by: Chris Aniszczyk --- .../eclipse/jgit/api/CheckoutCommandTest.java | 19 ++++++++++++++++++- .../org/eclipse/jgit/api/CheckoutCommand.java | 19 +++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java index cf78a0e56..1166464d5 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java @@ -52,6 +52,7 @@ import org.eclipse.jgit.api.errors.RefAlreadyExistsException; import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RepositoryTestCase; import org.eclipse.jgit.revwalk.RevCommit; @@ -97,9 +98,12 @@ public void testCheckout() { git.checkout().setName("test").call(); assertEquals("[Test.txt, mode:100644, content:Some change]", indexState(CONTENT)); - git.checkout().setName("master").call(); + Ref result = git.checkout().setName("master").call(); assertEquals("[Test.txt, mode:100644, content:Hello world]", indexState(CONTENT)); + assertEquals("refs/heads/master", result.getName()); + assertEquals("refs/heads/master", git.getRepository() + .getFullBranch()); } catch (Exception e) { fail(e.getMessage()); } @@ -171,4 +175,17 @@ public void testCheckoutWithNonDeletedFiles() throws Exception { fis.close(); } } + + public void testCheckoutCommit() { + try { + Ref result = git.checkout().setName(initialCommit.name()).call(); + assertEquals("[Test.txt, mode:100644, content:Hello world]", + indexState(CONTENT)); + assertNull(result); + assertEquals(initialCommit.name(), git.getRepository() + .getFullBranch()); + } catch (Exception e) { + fail(e.getMessage()); + } + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java index 2546231cf..cb261a0ac 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java @@ -128,7 +128,7 @@ public Ref call() throws JGitInternalException, RefAlreadyExistsException, String refLogMessage = "checkout: moving from " + headRef.getTarget().getName(); ObjectId branch = repo.resolve(name); - Ref ref = repo.getRef(name); + if (branch == null) throw new RefNotFoundException(MessageFormat.format(JGitText .get().refNotResolved, name)); @@ -148,11 +148,20 @@ public Ref call() throws JGitInternalException, RefAlreadyExistsException, status = new CheckoutResult(Status.CONFLICTS, fileList); throw e; } - RefUpdate refUpdate = repo.updateRef(Constants.HEAD); + Ref ref = repo.getRef(name); + if (ref != null && !ref.getName().startsWith(Constants.R_HEADS)) + ref = null; + RefUpdate refUpdate = repo.updateRef(Constants.HEAD, ref == null); refUpdate.setForceUpdate(force); refUpdate.setRefLogMessage(refLogMessage + "to " + newCommit.getName(), false); - Result updateResult = refUpdate.link(ref.getName()); + Result updateResult; + if (ref != null) + updateResult = refUpdate.link(ref.getName()); + else { + refUpdate.setNewObjectId(newCommit); + updateResult = refUpdate.forceUpdate(); + } setCallable(false); @@ -174,8 +183,6 @@ public Ref call() throws JGitInternalException, RefAlreadyExistsException, throw new JGitInternalException(MessageFormat.format(JGitText .get().checkoutUnexpectedResult, updateResult.name())); - Ref result = repo.getRef(name); - if (!repo.isBare() && !dco.getToBeDeleted().isEmpty()) { List fileList = new ArrayList(); for (String filePath : dco.getToBeDeleted()) { @@ -185,7 +192,7 @@ public Ref call() throws JGitInternalException, RefAlreadyExistsException, } else status = CheckoutResult.OK_RESULT; - return result; + return ref; } catch (IOException ioe) { throw new JGitInternalException(ioe.getMessage(), ioe); } finally {