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 <mathias.kinzler@sap.com>
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
This commit is contained in:
Mathias Kinzler 2010-12-20 10:35:10 +01:00 committed by Chris Aniszczyk
parent 0c22243c4a
commit 89a4dcf71f
2 changed files with 31 additions and 7 deletions

View File

@ -52,6 +52,7 @@
import org.eclipse.jgit.api.errors.RefAlreadyExistsException; import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RepositoryTestCase; import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
@ -97,9 +98,12 @@ public void testCheckout() {
git.checkout().setName("test").call(); git.checkout().setName("test").call();
assertEquals("[Test.txt, mode:100644, content:Some change]", assertEquals("[Test.txt, mode:100644, content:Some change]",
indexState(CONTENT)); indexState(CONTENT));
git.checkout().setName("master").call(); Ref result = git.checkout().setName("master").call();
assertEquals("[Test.txt, mode:100644, content:Hello world]", assertEquals("[Test.txt, mode:100644, content:Hello world]",
indexState(CONTENT)); indexState(CONTENT));
assertEquals("refs/heads/master", result.getName());
assertEquals("refs/heads/master", git.getRepository()
.getFullBranch());
} catch (Exception e) { } catch (Exception e) {
fail(e.getMessage()); fail(e.getMessage());
} }
@ -171,4 +175,17 @@ public void testCheckoutWithNonDeletedFiles() throws Exception {
fis.close(); 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());
}
}
} }

View File

@ -128,7 +128,7 @@ public Ref call() throws JGitInternalException, RefAlreadyExistsException,
String refLogMessage = "checkout: moving from " String refLogMessage = "checkout: moving from "
+ headRef.getTarget().getName(); + headRef.getTarget().getName();
ObjectId branch = repo.resolve(name); ObjectId branch = repo.resolve(name);
Ref ref = repo.getRef(name);
if (branch == null) if (branch == null)
throw new RefNotFoundException(MessageFormat.format(JGitText throw new RefNotFoundException(MessageFormat.format(JGitText
.get().refNotResolved, name)); .get().refNotResolved, name));
@ -148,11 +148,20 @@ public Ref call() throws JGitInternalException, RefAlreadyExistsException,
status = new CheckoutResult(Status.CONFLICTS, fileList); status = new CheckoutResult(Status.CONFLICTS, fileList);
throw e; 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.setForceUpdate(force);
refUpdate.setRefLogMessage(refLogMessage + "to " refUpdate.setRefLogMessage(refLogMessage + "to "
+ newCommit.getName(), false); + 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); setCallable(false);
@ -174,8 +183,6 @@ public Ref call() throws JGitInternalException, RefAlreadyExistsException,
throw new JGitInternalException(MessageFormat.format(JGitText throw new JGitInternalException(MessageFormat.format(JGitText
.get().checkoutUnexpectedResult, updateResult.name())); .get().checkoutUnexpectedResult, updateResult.name()));
Ref result = repo.getRef(name);
if (!repo.isBare() && !dco.getToBeDeleted().isEmpty()) { if (!repo.isBare() && !dco.getToBeDeleted().isEmpty()) {
List<File> fileList = new ArrayList<File>(); List<File> fileList = new ArrayList<File>();
for (String filePath : dco.getToBeDeleted()) { for (String filePath : dco.getToBeDeleted()) {
@ -185,7 +192,7 @@ public Ref call() throws JGitInternalException, RefAlreadyExistsException,
} }
else else
status = CheckoutResult.OK_RESULT; status = CheckoutResult.OK_RESULT;
return result; return ref;
} catch (IOException ioe) { } catch (IOException ioe) {
throw new JGitInternalException(ioe.getMessage(), ioe); throw new JGitInternalException(ioe.getMessage(), ioe);
} finally { } finally {