Add git checkout --orphan implementation
Change-Id: I7bb583674641efed210d3cd5b86af27d7bb48e97 Signed-off-by: SATO taichi <ryushi@gmail.com>
This commit is contained in:
parent
3db6e05e52
commit
2f425cf30c
|
@ -59,7 +59,9 @@
|
|||
|
||||
import org.eclipse.jgit.api.CheckoutResult.Status;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.api.errors.InvalidRefNameException;
|
||||
import org.eclipse.jgit.api.errors.JGitInternalException;
|
||||
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
|
||||
import org.eclipse.jgit.api.errors.RefNotFoundException;
|
||||
import org.eclipse.jgit.dircache.DirCache;
|
||||
import org.eclipse.jgit.dircache.DirCacheEntry;
|
||||
|
@ -351,4 +353,98 @@ public void testUpdateSmudgedEntries() throws Exception {
|
|||
assertEquals(size, entry.getLength());
|
||||
assertEquals(mTime, entry.getLastModified());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckoutOrphanBranch() throws Exception {
|
||||
CheckoutCommand co = newOrphanBranchCommand();
|
||||
assertCheckoutRef(co.call());
|
||||
|
||||
File HEAD = new File(trash, ".git/HEAD");
|
||||
String headRef = read(HEAD);
|
||||
assertEquals("ref: refs/heads/orphanbranch\n", headRef);
|
||||
assertEquals(2, trash.list().length);
|
||||
|
||||
File heads = new File(trash, ".git/refs/heads");
|
||||
assertEquals(2, heads.listFiles().length);
|
||||
|
||||
this.assertNoHead();
|
||||
this.assertRepositoryCondition(1);
|
||||
assertEquals(CheckoutResult.NOT_TRIED_RESULT, co.getResult());
|
||||
}
|
||||
|
||||
private CheckoutCommand newOrphanBranchCommand() {
|
||||
return git.checkout().setOrphan(true)
|
||||
.setName("orphanbranch");
|
||||
}
|
||||
|
||||
private static void assertCheckoutRef(Ref ref) {
|
||||
assertNotNull(ref);
|
||||
assertEquals("refs/heads/orphanbranch", ref.getTarget().getName());
|
||||
}
|
||||
|
||||
private void assertNoHead() throws IOException {
|
||||
assertNull(db.resolve("HEAD"));
|
||||
}
|
||||
|
||||
private void assertRepositoryCondition(int files) throws GitAPIException {
|
||||
org.eclipse.jgit.api.Status status = this.git.status().call();
|
||||
assertFalse(status.isClean());
|
||||
assertEquals(files, status.getAdded().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateOrphanBranchWithStartCommit() throws Exception {
|
||||
CheckoutCommand co = newOrphanBranchCommand();
|
||||
Ref ref = co.setStartPoint(initialCommit).call();
|
||||
assertCheckoutRef(ref);
|
||||
assertEquals(2, trash.list().length);
|
||||
this.assertNoHead();
|
||||
this.assertRepositoryCondition(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateOrphanBranchWithStartPoint() throws Exception {
|
||||
CheckoutCommand co = newOrphanBranchCommand();
|
||||
Ref ref = co.setStartPoint("HEAD^").call();
|
||||
assertCheckoutRef(ref);
|
||||
|
||||
assertEquals(2, trash.list().length);
|
||||
this.assertNoHead();
|
||||
this.assertRepositoryCondition(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidRefName() throws Exception {
|
||||
try {
|
||||
git.checkout().setOrphan(true).setName("../invalidname").call();
|
||||
fail("Should have failed");
|
||||
} catch (InvalidRefNameException e) {
|
||||
// except to hit here
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullRefName() throws Exception {
|
||||
try {
|
||||
git.checkout().setOrphan(true).setName(null).call();
|
||||
fail("Should have failed");
|
||||
} catch (InvalidRefNameException e) {
|
||||
// except to hit here
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlreadyExists() throws Exception {
|
||||
this.git.checkout().setCreateBranch(true).setName("orphanbranch")
|
||||
.call();
|
||||
this.git.checkout().setName("master").call();
|
||||
|
||||
try {
|
||||
newOrphanBranchCommand().call();
|
||||
fail("Should have failed");
|
||||
} catch (RefAlreadyExistsException e) {
|
||||
// except to hit here
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -158,6 +159,8 @@ private Stage(int number) {
|
|||
|
||||
private boolean createBranch = false;
|
||||
|
||||
private boolean orphan = false;
|
||||
|
||||
private CreateBranchCommand.SetupUpstreamMode upstreamMode;
|
||||
|
||||
private String startPoint = null;
|
||||
|
@ -197,8 +200,8 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
|
|||
RefNotFoundException, InvalidRefNameException,
|
||||
CheckoutConflictException {
|
||||
checkCallable();
|
||||
processOptions();
|
||||
try {
|
||||
processOptions();
|
||||
if (checkoutAllPaths || !paths.isEmpty()) {
|
||||
checkoutPaths();
|
||||
status = new CheckoutResult(Status.OK, paths);
|
||||
|
@ -219,10 +222,25 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
|
|||
Ref headRef = repo.getRef(Constants.HEAD);
|
||||
String shortHeadRef = getShortBranchName(headRef);
|
||||
String refLogMessage = "checkout: moving from " + shortHeadRef; //$NON-NLS-1$
|
||||
ObjectId branch = repo.resolve(name);
|
||||
if (branch == null)
|
||||
throw new RefNotFoundException(MessageFormat.format(JGitText
|
||||
.get().refNotResolved, name));
|
||||
ObjectId branch;
|
||||
if (orphan) {
|
||||
if (startPoint == null && startCommit == null) {
|
||||
Result r = repo.updateRef(Constants.HEAD).link(
|
||||
getBranchName());
|
||||
if (!EnumSet.of(Result.NEW, Result.FORCED).contains(r))
|
||||
throw new JGitInternalException(MessageFormat.format(
|
||||
JGitText.get().checkoutUnexpectedResult,
|
||||
r.name()));
|
||||
this.status = CheckoutResult.NOT_TRIED_RESULT;
|
||||
return repo.getRef(Constants.HEAD);
|
||||
}
|
||||
branch = getStartPoint();
|
||||
} else {
|
||||
branch = repo.resolve(name);
|
||||
if (branch == null)
|
||||
throw new RefNotFoundException(MessageFormat.format(
|
||||
JGitText.get().refNotResolved, name));
|
||||
}
|
||||
|
||||
RevWalk revWalk = new RevWalk(repo);
|
||||
AnyObjectId headId = headRef.getObjectId();
|
||||
|
@ -256,7 +274,10 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
|
|||
Result updateResult;
|
||||
if (ref != null)
|
||||
updateResult = refUpdate.link(ref.getName());
|
||||
else {
|
||||
else if (orphan) {
|
||||
updateResult = refUpdate.link(getBranchName());
|
||||
ref = repo.getRef(Constants.HEAD);
|
||||
} else {
|
||||
refUpdate.setNewObjectId(newCommit);
|
||||
updateResult = refUpdate.forceUpdate();
|
||||
}
|
||||
|
@ -465,12 +486,27 @@ private ObjectId getStartPoint() throws AmbiguousObjectException,
|
|||
return result;
|
||||
}
|
||||
|
||||
private void processOptions() throws InvalidRefNameException {
|
||||
if ((!checkoutAllPaths && paths.isEmpty())
|
||||
private void processOptions() throws InvalidRefNameException,
|
||||
RefAlreadyExistsException, IOException {
|
||||
if (((!checkoutAllPaths && paths.isEmpty()) || orphan)
|
||||
&& (name == null || !Repository
|
||||
.isValidRefName(Constants.R_HEADS + name)))
|
||||
throw new InvalidRefNameException(MessageFormat.format(JGitText
|
||||
.get().branchNameInvalid, name == null ? "<null>" : name)); //$NON-NLS-1$
|
||||
|
||||
if (orphan) {
|
||||
Ref refToCheck = repo.getRef(getBranchName());
|
||||
if (refToCheck != null)
|
||||
throw new RefAlreadyExistsException(MessageFormat.format(
|
||||
JGitText.get().refAlreadyExists, name));
|
||||
}
|
||||
}
|
||||
|
||||
private String getBranchName() {
|
||||
if (name.startsWith(Constants.R_REFS))
|
||||
return name;
|
||||
|
||||
return Constants.R_HEADS + name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -516,6 +552,25 @@ public CheckoutCommand setCreateBranch(boolean createBranch) {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to create a new orphan branch.
|
||||
* <p>
|
||||
* If <code>true</code> is used, the name of the new orphan branch must be
|
||||
* set using {@link #setName(String)}. The commit at which to start the new
|
||||
* orphan branch can be set using {@link #setStartPoint(String)} or
|
||||
* {@link #setStartPoint(RevCommit)}; if not specified, HEAD is used.
|
||||
*
|
||||
* @param orphan
|
||||
* if <code>true</code> a orphan branch will be created as part
|
||||
* of the checkout to the specified start point
|
||||
* @return this instance
|
||||
*/
|
||||
public CheckoutCommand setOrphan(boolean orphan) {
|
||||
checkCallable();
|
||||
this.orphan = orphan;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify to force the ref update in case of a branch switch.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue