@ -58,7 +58,13 @@ import org.eclipse.jgit.transport.PushCertificate;
* Creates , updates or deletes any reference .
* Creates , updates or deletes any reference .
* /
* /
public abstract class RefUpdate {
public abstract class RefUpdate {
/** Status of an update request. */
/ * *
* Status of an update request .
* < p >
* New values may be added to this enum in the future . Callers may assume that
* unknown values are failures , and may generally treat them the same as
* { @link # REJECTED_OTHER_REASON } .
* /
public static enum Result {
public static enum Result {
/** The ref update/delete has not been attempted by the caller. */
/** The ref update/delete has not been attempted by the caller. */
NOT_ATTEMPTED ,
NOT_ATTEMPTED ,
@ -114,6 +120,10 @@ public abstract class RefUpdate {
* merged into the new value . The configuration did not allow a forced
* merged into the new value . The configuration did not allow a forced
* update / delete to take place , so ref still contains the old value . No
* update / delete to take place , so ref still contains the old value . No
* previous history was lost .
* previous history was lost .
* < p >
* < em > Note : < / em > Despite the general name , this result only refers to the
* non - fast - forward case . For more general errors , see { @link
* # REJECTED_OTHER_REASON } .
* /
* /
REJECTED ,
REJECTED ,
@ -139,7 +149,25 @@ public abstract class RefUpdate {
* The ref was renamed from another name
* The ref was renamed from another name
* < p >
* < p >
* /
* /
RENAMED
RENAMED ,
/ * *
* One or more objects aren ' t in the repository .
* < p >
* This is severe indication of either repository corruption on the
* server side , or a bug in the client wherein the client did not supply
* all required objects during the pack transfer .
*
* @since 4 . 9
* /
REJECTED_MISSING_OBJECT ,
/ * *
* Rejected for some other reason not covered by another enum value .
*
* @since 4 . 9
* /
REJECTED_OTHER_REASON ;
}
}
/** New value the caller wants this ref to have. */
/** New value the caller wants this ref to have. */
@ -637,34 +665,47 @@ public abstract class RefUpdate {
RevObject oldObj ;
RevObject oldObj ;
// don't make expensive conflict check if this is an existing Ref
// don't make expensive conflict check if this is an existing Ref
if ( oldValue = = null & & checkConflicting & & getRefDatabase ( ) . isNameConflicting ( getName ( ) ) )
if ( oldValue = = null & & checkConflicting
& & getRefDatabase ( ) . isNameConflicting ( getName ( ) ) ) {
return Result . LOCK_FAILURE ;
return Result . LOCK_FAILURE ;
}
try {
try {
// If we're detaching a symbolic reference, we should update the reference
// If we're detaching a symbolic reference, we should update the reference
// itself. Otherwise, we will update the leaf reference, which should be
// itself. Otherwise, we will update the leaf reference, which should be
// an ObjectIdRef.
// an ObjectIdRef.
if ( ! tryLock ( ! detachingSymbolicRef ) )
if ( ! tryLock ( ! detachingSymbolicRef ) ) {
return Result . LOCK_FAILURE ;
return Result . LOCK_FAILURE ;
}
if ( expValue ! = null ) {
if ( expValue ! = null ) {
final ObjectId o ;
final ObjectId o ;
o = oldValue ! = null ? oldValue : ObjectId . zeroId ( ) ;
o = oldValue ! = null ? oldValue : ObjectId . zeroId ( ) ;
if ( ! AnyObjectId . equals ( expValue , o ) )
if ( ! AnyObjectId . equals ( expValue , o ) ) {
return Result . LOCK_FAILURE ;
return Result . LOCK_FAILURE ;
}
}
try {
newObj = safeParseNew ( walk , newValue ) ;
} catch ( MissingObjectException e ) {
return Result . REJECTED_MISSING_OBJECT ;
}
}
if ( oldValue = = null )
if ( oldValue = = null ) {
return store . execute ( Result . NEW ) ;
return store . execute ( Result . NEW ) ;
}
newObj = safeParse ( walk , newValue ) ;
oldObj = safeParseOld ( walk , oldValue ) ;
oldObj = safeParse ( walk , oldValue ) ;
if ( newObj = = oldObj & & ! detachingSymbolicRef ) {
if ( newObj = = oldObj & & ! detachingSymbolicRef )
return store . execute ( Result . NO_CHANGE ) ;
return store . execute ( Result . NO_CHANGE ) ;
}
if ( isForceUpdate ( ) )
if ( isForceUpdate ( ) ) {
return store . execute ( Result . FORCED ) ;
return store . execute ( Result . FORCED ) ;
}
if ( newObj instanceof RevCommit & & oldObj instanceof RevCommit ) {
if ( newObj instanceof RevCommit & & oldObj instanceof RevCommit ) {
if ( walk . isMergedInto ( ( RevCommit ) oldObj , ( RevCommit ) newObj ) )
if ( walk . isMergedInto ( ( RevCommit ) oldObj , ( RevCommit ) newObj ) ) {
return store . execute ( Result . FAST_FORWARD ) ;
return store . execute ( Result . FAST_FORWARD ) ;
}
}
}
return Result . REJECTED ;
return Result . REJECTED ;
@ -684,16 +725,23 @@ public abstract class RefUpdate {
checkConflicting = check ;
checkConflicting = check ;
}
}
private static RevObject safeParse ( final RevWalk rw , final AnyObjectId id )
private static RevObject safeParseNew ( RevWalk rw , AnyObjectId newId )
throws IOException {
if ( newId = = null | | ObjectId . zeroId ( ) . equals ( newId ) ) {
return null ;
}
return rw . parseAny ( newId ) ;
}
private static RevObject safeParseOld ( RevWalk rw , AnyObjectId oldId )
throws IOException {
throws IOException {
try {
try {
return id ! = null ? rw . parseAny ( id ) : null ;
return oldI d ! = null ? rw . parseAny ( oldI d) : null ;
} catch ( MissingObjectException e ) {
} catch ( MissingObjectException e ) {
// We can expect some objects to be missing, like if we are
// We can expect some old objects to be missing, like if we are trying to
// trying to force a deletion of a branch and the object it
// force a deletion of a branch and the object it points to has been
// points to has been pruned from the database due to freak
// pruned from the database due to freak corruption accidents (it happens
// corruption accidents (it happens with 'git new-work-dir').
// with 'git new-work-dir').
//
return null ;
return null ;
}
}
}
}