diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java index 5ad913c56..d55856ace 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java @@ -48,6 +48,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import java.io.IOException; @@ -181,6 +182,24 @@ public void testParseGitDescribeOutput() throws IOException { assertEquals(db.resolve("b~2"), db.resolve("B-6-g7f82283~2")); } + @Test + public void testParseNonGitDescribe() throws IOException { + ObjectId id = id("49322bb17d3acc9146f98c97d078513228bbf3c0"); + RefUpdate ru = db.updateRef("refs/heads/foo-g032c"); + ru.setNewObjectId(id); + assertSame(RefUpdate.Result.NEW, ru.update()); + + assertEquals(id, db.resolve("refs/heads/foo-g032c")); + assertEquals(id, db.resolve("foo-g032c")); + + ru = db.updateRef("refs/heads/foo-g032c-dev"); + ru.setNewObjectId(id); + assertSame(RefUpdate.Result.NEW, ru.update()); + + assertEquals(id, db.resolve("refs/heads/foo-g032c-dev")); + assertEquals(id, db.resolve("foo-g032c-dev")); + } + @Test public void testParseLookupPath() throws IOException { ObjectId b2_txt = id("10da5895682013006950e7da534b705252b03be6"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java index bb009e913..8b904bb2c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java @@ -169,7 +169,7 @@ public void testUpdateCreateRef() throws IOException { */ @Test public void testUpdateDelete() throws IOException { - final RemoteRefUpdate rru = new RemoteRefUpdate(db, null, + final RemoteRefUpdate rru = new RemoteRefUpdate(db, (String) null, "refs/heads/master", false, null, null); final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master", ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9")); @@ -184,7 +184,7 @@ public void testUpdateDelete() throws IOException { */ @Test public void testUpdateDeleteNonExisting() throws IOException { - final RemoteRefUpdate rru = new RemoteRefUpdate(db, null, + final RemoteRefUpdate rru = new RemoteRefUpdate(db, (String) null, "refs/heads/master", false, null, null); testOneUpdateStatus(rru, null, Status.NON_EXISTING, null); } @@ -279,12 +279,12 @@ public void testUpdateRejectedByConnection() throws IOException { */ @Test public void testUpdateMixedCases() throws IOException { - final RemoteRefUpdate rruOk = new RemoteRefUpdate(db, null, + final RemoteRefUpdate rruOk = new RemoteRefUpdate(db, (String) null, "refs/heads/master", false, null, null); final Ref refToChange = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master", ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9")); - final RemoteRefUpdate rruReject = new RemoteRefUpdate(db, null, - "refs/heads/nonexisting", false, null, null); + final RemoteRefUpdate rruReject = new RemoteRefUpdate(db, + (String) null, "refs/heads/nonexisting", false, null, null); refUpdates.add(rruOk); refUpdates.add(rruReject); advertisedRefs.add(refToChange); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java index c4d2d73bc..6916a86f4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -577,24 +577,6 @@ private ObjectId resolve(final RevWalk rw, final String revstr) throws IOExcepti revstr); i = m - 1; break; - case '-': - if (i + 4 < rev.length && rev[i + 1] == 'g' - && isHex(rev[i + 2]) && isHex(rev[i + 3])) { - // Possibly output from git describe? - // Resolve longest valid abbreviation. - int cnt = 2; - while (i + 2 + cnt < rev.length && isHex(rev[i + 2 + cnt])) - cnt++; - String s = new String(rev, i + 2, cnt); - if (AbbreviatedObjectId.isId(s)) { - ObjectId id = resolveAbbreviation(s); - if (id != null) { - ref = rw.parseAny(id); - i += 1 + s.length(); - } - } - } - break; case ':': { RevTree tree; if (ref == null) { @@ -637,6 +619,14 @@ private static boolean isHex(char c) { || ('A' <= c && c <= 'F'); } + private static boolean isAllHex(String str, int ptr) { + while (ptr < str.length()) { + if (!isHex(str.charAt(ptr++))) + return false; + } + return true; + } + private RevObject parseSimple(RevWalk rw, String revstr) throws IOException { ObjectId id = resolveSimple(revstr); return id != null ? rw.parseAny(id) : null; @@ -653,6 +643,17 @@ private ObjectId resolveSimple(final String revstr) throws IOException { if (AbbreviatedObjectId.isId(revstr)) return resolveAbbreviation(revstr); + int dashg = revstr.indexOf("-g"); + if (4 < revstr.length() && 0 <= dashg + && isHex(revstr.charAt(dashg + 2)) + && isHex(revstr.charAt(dashg + 3)) + && isAllHex(revstr, dashg + 4)) { + // Possibly output from git describe? + String s = revstr.substring(dashg + 2); + if (AbbreviatedObjectId.isId(s)) + return resolveAbbreviation(s); + } + return null; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java index 406767f84..e91c87302 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java @@ -48,6 +48,7 @@ import org.eclipse.jgit.JGitText; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevWalk; @@ -185,14 +186,117 @@ public RemoteRefUpdate(final Repository localDb, final String srcRef, final String remoteName, final boolean forceUpdate, final String localName, final ObjectId expectedOldObjectId) throws IOException { + this(localDb, srcRef, srcRef != null ? localDb.resolve(srcRef) + : ObjectId.zeroId(), remoteName, forceUpdate, localName, + expectedOldObjectId); + } + + /** + * Construct remote ref update request by providing an update specification. + * Object is created with default {@link Status#NOT_ATTEMPTED} status and no + * message. + * + * @param localDb + * local repository to push from. + * @param srcRef + * source revision. Use null to delete. + * @param remoteName + * full name of a remote ref to update, e.g. "refs/heads/master" + * (no wildcard, no short name). + * @param forceUpdate + * true when caller want remote ref to be updated regardless + * whether it is fast-forward update (old object is ancestor of + * new object). + * @param localName + * optional full name of a local stored tracking branch, to + * update after push, e.g. "refs/remotes/zawir/dirty" (no + * wildcard, no short name); null if no local tracking branch + * should be updated. + * @param expectedOldObjectId + * optional object id that caller is expecting, requiring to be + * advertised by remote side before update; update will take + * place ONLY if remote side advertise exactly this expected id; + * null if caller doesn't care what object id remote side + * advertise. Use {@link ObjectId#zeroId()} when expecting no + * remote ref with this name. + * @throws IOException + * when I/O error occurred during creating + * {@link TrackingRefUpdate} for local tracking branch or srcRef + * can't be resolved to any object. + * @throws IllegalArgumentException + * if some required parameter was null + */ + public RemoteRefUpdate(final Repository localDb, final Ref srcRef, + final String remoteName, final boolean forceUpdate, + final String localName, final ObjectId expectedOldObjectId) + throws IOException { + this(localDb, srcRef != null ? srcRef.getName() : null, + srcRef != null ? srcRef.getObjectId() : null, remoteName, + forceUpdate, localName, expectedOldObjectId); + } + + /** + * Construct remote ref update request by providing an update specification. + * Object is created with default {@link Status#NOT_ATTEMPTED} status and no + * message. + * + * @param localDb + * local repository to push from. + * @param srcRef + * source revision to label srcId with. If null srcId.name() will + * be used instead. + * @param srcId + * The new object that the caller wants remote ref to be after + * update. Use null or {@link ObjectId#zeroId()} for delete + * request. + * @param remoteName + * full name of a remote ref to update, e.g. "refs/heads/master" + * (no wildcard, no short name). + * @param forceUpdate + * true when caller want remote ref to be updated regardless + * whether it is fast-forward update (old object is ancestor of + * new object). + * @param localName + * optional full name of a local stored tracking branch, to + * update after push, e.g. "refs/remotes/zawir/dirty" (no + * wildcard, no short name); null if no local tracking branch + * should be updated. + * @param expectedOldObjectId + * optional object id that caller is expecting, requiring to be + * advertised by remote side before update; update will take + * place ONLY if remote side advertise exactly this expected id; + * null if caller doesn't care what object id remote side + * advertise. Use {@link ObjectId#zeroId()} when expecting no + * remote ref with this name. + * @throws IOException + * when I/O error occurred during creating + * {@link TrackingRefUpdate} for local tracking branch or srcRef + * can't be resolved to any object. + * @throws IllegalArgumentException + * if some required parameter was null + */ + public RemoteRefUpdate(final Repository localDb, final String srcRef, + final ObjectId srcId, final String remoteName, + final boolean forceUpdate, final String localName, + final ObjectId expectedOldObjectId) throws IOException { if (remoteName == null) throw new IllegalArgumentException(JGitText.get().remoteNameCantBeNull); - this.srcRef = srcRef; - this.newObjectId = (srcRef == null ? ObjectId.zeroId() : localDb - .resolve(srcRef)); - if (newObjectId == null) + if (srcId == null && srcRef != null) throw new IOException(MessageFormat.format( JGitText.get().sourceRefDoesntResolveToAnyObject, srcRef)); + + if (srcRef != null) + this.srcRef = srcRef; + else if (srcId != null && !srcId.equals(ObjectId.zeroId())) + this.srcRef = srcId.name(); + else + this.srcRef = null; + + if (srcId != null) + this.newObjectId = srcId; + else + this.newObjectId = ObjectId.zeroId(); + this.remoteName = remoteName; this.forceUpdate = forceUpdate; if (localName != null && localDb != null)