@ -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 {
} finally {
rw . release ( ) ;
rw . release ( ) ;
}
}
}
}
private ObjectId resolve ( final RevWalk rw , final String revstr ) throws IOException {
/ * *
* 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 {
rw . release ( ) ;
}
}
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 ) ;
if ( name . equals ( "" ) )
// Currently checked out branch, HEAD if
// detached
name = Constants . HEAD ;
Ref ref = getRef ( name ) ;
if ( ref = = null )
return null ;
return null ;
rev = resolveReflog ( rw , resolved , time ) ;
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 )
if ( rev = = null )
return null ;
return null ;
tree = rw . parseTree ( id ) ;
} else {
tree = rw . parseTree ( rev ) ;
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 )