@@ -47,6 +47,7 @@ import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertSame; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
@@ -239,4 +240,20 @@ public class CheckoutCommandTest extends RepositoryTestCase { | |||
fail(e.getMessage()); | |||
} | |||
} | |||
@Test | |||
public void testDetachedHeadOnCheckout() throws JGitInternalException, | |||
RefAlreadyExistsException, RefNotFoundException, | |||
InvalidRefNameException, IOException { | |||
CheckoutCommand co = git.checkout(); | |||
co.setName("master").call(); | |||
String commitId = db.getRef(Constants.MASTER).getObjectId().name(); | |||
co = git.checkout(); | |||
co.setName(commitId).call(); | |||
Ref head = db.getRef(Constants.HEAD); | |||
assertFalse(head.isSymbolic()); | |||
assertSame(head, head.getTarget()); | |||
} | |||
} |
@@ -167,6 +167,17 @@ public abstract class RefUpdate { | |||
private final Ref ref; | |||
/** | |||
* Is this RefUpdate detaching a symbolic ref? | |||
* | |||
* We need this info since this.ref will normally be peeled of in case of | |||
* detaching a symbolic ref (HEAD for example). | |||
* | |||
* Without this flag we cannot decide whether the ref has to be updated or | |||
* not in case when it was a symbolic ref and the newValue == oldValue. | |||
*/ | |||
private boolean detachingSymbolicRef; | |||
/** | |||
* Construct a new update operation for the reference. | |||
* <p> | |||
@@ -253,6 +264,13 @@ public abstract class RefUpdate { | |||
return newValue; | |||
} | |||
/** | |||
* Tells this RefUpdate that it is actually detaching a symbolic ref. | |||
*/ | |||
public void setDetachingSymbolicRef() { | |||
detachingSymbolicRef = true; | |||
} | |||
/** | |||
* Set the new value the ref will update to. | |||
* | |||
@@ -596,7 +614,7 @@ public abstract class RefUpdate { | |||
newObj = safeParse(walk, newValue); | |||
oldObj = safeParse(walk, oldValue); | |||
if (newObj == oldObj) | |||
if (newObj == oldObj && !detachingSymbolicRef) | |||
return store.execute(Result.NO_CHANGE); | |||
if (newObj instanceof RevCommit && oldObj instanceof RevCommit) { |
@@ -491,15 +491,22 @@ public class RefDirectory extends RefDatabase { | |||
public RefDirectoryUpdate newUpdate(String name, boolean detach) | |||
throws IOException { | |||
boolean detachingSymbolicRef = false; | |||
final RefList<Ref> packed = getPackedRefs(); | |||
Ref ref = readRef(name, packed); | |||
if (ref != null) | |||
ref = resolve(ref, 0, null, null, packed); | |||
if (ref == null) | |||
ref = new ObjectIdRef.Unpeeled(NEW, name, null); | |||
else if (detach && ref.isSymbolic()) | |||
ref = new ObjectIdRef.Unpeeled(LOOSE, name, ref.getObjectId()); | |||
return new RefDirectoryUpdate(this, ref); | |||
else { | |||
detachingSymbolicRef = detach && ref.isSymbolic(); | |||
if (detachingSymbolicRef) | |||
ref = new ObjectIdRef.Unpeeled(LOOSE, name, ref.getObjectId()); | |||
} | |||
RefDirectoryUpdate refDirUpdate = new RefDirectoryUpdate(this, ref); | |||
if (detachingSymbolicRef) | |||
refDirUpdate.setDetachingSymbolicRef(); | |||
return refDirUpdate; | |||
} | |||
@Override |