Browse Source

Merge changes I98df46ce,Ifb815a12,I051a1724

* changes:
  Support [<ref>]@{upstream} revision syntax
  Support parsing previous checkout as a revision expresion.
  Allow a @ without branch in revision syntax
stable-2.1
Robin Rosenberg 12 years ago committed by Gerrit Code Review @ Eclipse.org
parent
commit
5e21a8916c
  1. 61
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
  2. 35
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
  3. 179
      org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java

61
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java

@ -71,6 +71,38 @@ public class ReflogResolveTest extends RepositoryTestCase {
assertEquals(c1, db.resolve("master@{1}")); assertEquals(c1, db.resolve("master@{1}"));
} }
@Test
public void resolveUnnamedCurrentBranchCommits() throws Exception {
Git git = new Git(db);
writeTrashFile("file.txt", "content");
git.add().addFilepattern("file.txt").call();
RevCommit c1 = git.commit().setMessage("create file").call();
writeTrashFile("file.txt", "content2");
git.add().addFilepattern("file.txt").call();
RevCommit c2 = git.commit().setMessage("edit file").call();
assertEquals(c2, db.resolve("master@{0}"));
assertEquals(c1, db.resolve("master@{1}"));
git.checkout().setCreateBranch(true).setName("newbranch")
.setStartPoint(c1).call();
// same as current branch, e.g. master
assertEquals(c1, db.resolve("@{0}"));
try {
assertEquals(c1, db.resolve("@{1}"));
fail(); // Looking at wrong ref, e.g HEAD
} catch (RevisionSyntaxException e) {
assertNotNull(e);
}
// detached head, read HEAD reflog
git.checkout().setName(c2.getName()).call();
assertEquals(c2, db.resolve("@{0}"));
assertEquals(c1, db.resolve("@{1}"));
assertEquals(c2, db.resolve("@{2}"));
}
@Test @Test
public void resolveReflogParent() throws Exception { public void resolveReflogParent() throws Exception {
Git git = new Git(db); Git git = new Git(db);
@ -94,17 +126,36 @@ public class ReflogResolveTest extends RepositoryTestCase {
} }
@Test @Test
public void resolveNegativeEntryNumber() throws Exception { public void resolvePreviousBranch() throws Exception {
Git git = new Git(db); Git git = new Git(db);
writeTrashFile("file.txt", "content"); writeTrashFile("file.txt", "content");
git.add().addFilepattern("file.txt").call(); git.add().addFilepattern("file.txt").call();
git.commit().setMessage("create file").call(); RevCommit c1 = git.commit().setMessage("create file").call();
writeTrashFile("file.txt", "content2");
git.add().addFilepattern("file.txt").call();
RevCommit c2 = git.commit().setMessage("edit file").call();
git.checkout().setCreateBranch(true).setName("newbranch")
.setStartPoint(c1).call();
git.checkout().setName(c1.getName()).call();
git.checkout().setName("master").call();
assertEquals(c1.getName(), db.simplify("@{-1}"));
assertEquals("newbranch", db.simplify("@{-2}"));
assertEquals("master", db.simplify("@{-3}"));
// chained expression
try { try {
db.resolve("master@{-12}"); // Cannot refer to reflog of detached head
fail("Exception not thrown"); db.resolve("@{-1}@{0}");
fail();
} catch (RevisionSyntaxException e) { } catch (RevisionSyntaxException e) {
assertNotNull(e);
} }
assertEquals(c1.getName(), db.resolve("@{-2}@{0}").getName());
assertEquals(c2.getName(), db.resolve("@{-3}@{0}").getName());
} }
@Test @Test

35
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java

@ -53,7 +53,9 @@ import static org.junit.Assert.fail;
import java.io.IOException; import java.io.IOException;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test; import org.junit.Test;
public class RepositoryResolveTest extends SampleDataRepositoryTestCase { public class RepositoryResolveTest extends SampleDataRepositoryTestCase {
@ -231,6 +233,39 @@ public class RepositoryResolveTest extends SampleDataRepositoryTestCase {
assertNull("no not-a-branch:", db.resolve("not-a-branch:")); assertNull("no not-a-branch:", db.resolve("not-a-branch:"));
} }
@Test
public void resolveExprSimple() throws Exception {
Git git = new Git(db);
writeTrashFile("file.txt", "content");
git.add().addFilepattern("file.txt").call();
git.commit().setMessage("create file").call();
assertEquals("master", db.simplify("master"));
assertEquals("refs/heads/master", db.simplify("refs/heads/master"));
assertEquals("HEAD", db.simplify("HEAD"));
}
@Test
public void resolveUpstream() throws Exception {
Git git = new Git(db);
writeTrashFile("file.txt", "content");
git.add().addFilepattern("file.txt").call();
RevCommit c1 = git.commit().setMessage("create file").call();
writeTrashFile("file2.txt", "content");
RefUpdate updateRemoteRef = db.updateRef("refs/remotes/origin/main");
updateRemoteRef.setNewObjectId(c1);
updateRemoteRef.update();
db.getConfig().setString("branch", "master", "remote", "origin");
db.getConfig()
.setString("branch", "master", "merge", "refs/heads/main");
db.getConfig().setString("remote", "origin", "url",
"git://example.com/here");
db.getConfig().setString("remote", "origin", "fetch",
"+refs/heads/*:refs/remotes/origin/*");
git.add().addFilepattern("file2.txt").call();
git.commit().setMessage("create file").call();
assertEquals("refs/remotes/origin/main", db.simplify("@{upstream}"));
}
private static ObjectId id(String name) { private static ObjectId id(String name) {
return ObjectId.fromString(name); return ObjectId.fromString(name);
} }

179
org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java

@ -51,6 +51,7 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -79,8 +80,11 @@ import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.CheckoutEntry;
import org.eclipse.jgit.storage.file.ReflogEntry; import org.eclipse.jgit.storage.file.ReflogEntry;
import org.eclipse.jgit.storage.file.ReflogReader; import org.eclipse.jgit.storage.file.ReflogReader;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FileUtils;
@ -376,20 +380,58 @@ public abstract class Repository {
throws AmbiguousObjectException, IOException { throws AmbiguousObjectException, IOException {
RevWalk rw = new RevWalk(this); RevWalk rw = new RevWalk(this);
try { try {
return resolve(rw, revstr); Object resolved = resolve(rw, revstr);
if (resolved instanceof String) {
return getRef((String) resolved).getLeaf().getObjectId();
} else {
return (ObjectId) resolved;
}
} finally {
rw.release();
}
}
/**
* Simplify an expression, but unlike {@link #resolve(String)} it will not
* resolve a branch passed or resulting from the expression, such as @{-}.
* Thus this method can be used to process an expression to a method that
* expects a branch or revision id.
*
* @param revstr
* @return object id or ref name from resolved expression
* @throws AmbiguousObjectException
* @throws IOException
*/
public String simplify(final String revstr)
throws AmbiguousObjectException, IOException {
RevWalk rw = new RevWalk(this);
try {
Object resolved = resolve(rw, revstr);
if (resolved != null)
if (resolved instanceof String)
return (String) resolved;
else
return ((AnyObjectId) resolved).getName();
return null;
} finally { } finally {
rw.release(); rw.release();
} }
} }
private ObjectId resolve(final RevWalk rw, final String revstr) throws IOException { private Object resolve(final RevWalk rw, final String revstr)
throws IOException {
char[] revChars = revstr.toCharArray(); char[] revChars = revstr.toCharArray();
RevObject rev = null; RevObject rev = null;
String name = null;
int done = 0;
for (int i = 0; i < revChars.length; ++i) { for (int i = 0; i < revChars.length; ++i) {
switch (revChars[i]) { switch (revChars[i]) {
case '^': case '^':
if (rev == null) { if (rev == null) {
rev = parseSimple(rw, new String(revChars, 0, i)); if (name == null)
name = new String(revChars, done, i);
rev = parseSimple(rw, name);
name = null;
if (rev == null) if (rev == null)
return null; return null;
} }
@ -429,6 +471,7 @@ public abstract class Repository {
rev = commit.getParent(pnum - 1); rev = commit.getParent(pnum - 1);
} }
i = j - 1; i = j - 1;
done = i;
break; break;
case '{': case '{':
int k; int k;
@ -456,6 +499,7 @@ public abstract class Repository {
throw new RevisionSyntaxException(revstr); throw new RevisionSyntaxException(revstr);
else else
throw new RevisionSyntaxException(revstr); throw new RevisionSyntaxException(revstr);
done = k;
break; break;
default: default:
rev = rw.parseAny(rev); rev = rw.parseAny(rev);
@ -485,7 +529,9 @@ public abstract class Repository {
break; break;
case '~': case '~':
if (rev == null) { if (rev == null) {
rev = parseSimple(rw, new String(revChars, 0, i)); if (name == null)
name = new String(revChars, done, i);
rev = parseSimple(rw, name);
if (rev == null) if (rev == null)
return null; return null;
} }
@ -523,6 +569,8 @@ public abstract class Repository {
i = l - 1; i = l - 1;
break; break;
case '@': case '@':
if (rev != null)
throw new RevisionSyntaxException(revstr);
int m; int m;
String time = null; String time = null;
for (m = i + 2; m < revChars.length; ++m) { for (m = i + 2; m < revChars.length; ++m) {
@ -532,35 +580,86 @@ public abstract class Repository {
} }
} }
if (time != null) { if (time != null) {
String refName = new String(revChars, 0, i); if (time.equals("upstream")) {
Ref resolved = getRefDatabase().getRef(refName); if (name == null)
if (resolved == null) name = new String(revChars, done, i);
return null; if (name.equals(""))
rev = resolveReflog(rw, resolved, time); // Currently checked out branch, HEAD if
// detached
name = Constants.HEAD;
Ref ref = getRef(name);
if (ref == null)
return null;
if (ref.isSymbolic())
ref = ref.getLeaf();
name = ref.getName();
RemoteConfig remoteConfig;
try {
remoteConfig = new RemoteConfig(getConfig(),
"origin");
} catch (URISyntaxException e) {
throw new RevisionSyntaxException(revstr);
}
String remoteBranchName = getConfig()
.getString(
ConfigConstants.CONFIG_BRANCH_SECTION,
Repository.shortenRefName(ref.getName()),
ConfigConstants.CONFIG_KEY_MERGE);
List<RefSpec> fetchRefSpecs = remoteConfig
.getFetchRefSpecs();
for (RefSpec refSpec : fetchRefSpecs) {
if (refSpec.matchSource(remoteBranchName)) {
RefSpec expandFromSource = refSpec
.expandFromSource(remoteBranchName);
name = expandFromSource.getDestination();
break;
}
}
if (name == null)
throw new RevisionSyntaxException(revstr);
} else if (time.matches("^-\\d+$")) {
if (name != null)
throw new RevisionSyntaxException(revstr);
else {
String previousCheckout = resolveReflogCheckout(-Integer
.parseInt(time));
if (ObjectId.isId(previousCheckout))
rev = parseSimple(rw, previousCheckout);
else
name = previousCheckout;
}
} else {
if (name == null)
name = new String(revChars, done, i);
if (name.equals(""))
name = Constants.HEAD;
Ref ref = getRef(name);
if (ref == null)
return null;
// @{n} means current branch, not HEAD@{1} unless
// detached
if (ref.isSymbolic())
ref = ref.getLeaf();
rev = resolveReflog(rw, ref, time);
name = null;
}
i = m; i = m;
} else } else
i = m - 1; throw new RevisionSyntaxException(revstr);
break; break;
case ':': { case ':': {
RevTree tree; RevTree tree;
if (rev == null) { if (rev == null) {
// We might not yet have parsed the left hand side. if (name == null)
ObjectId id; name = new String(revChars, done, i);
try { if (name.equals(""))
if (i == 0) name = Constants.HEAD;
id = resolve(rw, Constants.HEAD); rev = parseSimple(rw, name);
else
id = resolve(rw, new String(revChars, 0, i));
} catch (RevisionSyntaxException badSyntax) {
throw new RevisionSyntaxException(revstr);
}
if (id == null)
return null;
tree = rw.parseTree(id);
} else {
tree = rw.parseTree(rev);
} }
if (rev == null)
return null;
tree = rw.parseTree(rev);
if (i == revChars.length - 1) if (i == revChars.length - 1)
return tree.copy(); return tree.copy();
@ -569,13 +668,19 @@ public abstract class Repository {
tree); tree);
return tw != null ? tw.getObjectId(0) : null; return tw != null ? tw.getObjectId(0) : null;
} }
default: default:
if (rev != null) if (rev != null)
throw new RevisionSyntaxException(revstr); throw new RevisionSyntaxException(revstr);
} }
} }
return rev != null ? rev.copy() : resolveSimple(revstr); if (rev != null)
return rev.copy();
if (name != null)
return name;
name = revstr.substring(done);
if (getRef(name) != null)
return name;
return resolveSimple(name);
} }
private static boolean isHex(char c) { private static boolean isHex(char c) {
@ -622,6 +727,19 @@ public abstract class Repository {
return null; return null;
} }
private String resolveReflogCheckout(int checkoutNo)
throws IOException {
List<ReflogEntry> reflogEntries = new ReflogReader(this, Constants.HEAD)
.getReverseEntries();
for (ReflogEntry entry : reflogEntries) {
CheckoutEntry checkout = entry.parseCheckout();
if (checkout != null)
if (checkoutNo-- == 1)
return checkout.getFromBranch();
}
return null;
}
private RevCommit resolveReflog(RevWalk rw, Ref ref, String time) private RevCommit resolveReflog(RevWalk rw, Ref ref, String time)
throws IOException { throws IOException {
int number; int number;
@ -631,10 +749,7 @@ public abstract class Repository {
throw new RevisionSyntaxException(MessageFormat.format( throw new RevisionSyntaxException(MessageFormat.format(
JGitText.get().invalidReflogRevision, time)); JGitText.get().invalidReflogRevision, time));
} }
if (number < 0) assert number >= 0;
throw new RevisionSyntaxException(MessageFormat.format(
JGitText.get().invalidReflogRevision, time));
ReflogReader reader = new ReflogReader(this, ref.getName()); ReflogReader reader = new ReflogReader(this, ref.getName());
ReflogEntry entry = reader.getReverseEntry(number); ReflogEntry entry = reader.getReverseEntry(number);
if (entry == null) if (entry == null)

Loading…
Cancel
Save