Browse Source

Support resolving integer-based reflog revisions

Revision strings such as 'master@{0}' can now be resolved
by Repository.resolve by reading the reflog for the ref and
returning the commit for the entry number specified.

This still throws an exception for cases not supported
such as 'master@{yesterday}'.

Change-Id: I6162777d6510e083565a77cac4545cda5a9aefb3
tags/v1.3.0.201202121842-rc4
Kevin Sawicki 12 years ago
parent
commit
dc4c06e7ac

+ 123
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java View File

@@ -0,0 +1,123 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.lib;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;

/**
* Unit tests for resolving reflog-based revisions
*/
public class ReflogResolveTest extends RepositoryTestCase {

@Test
public void resolveMasterCommits() 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}"));
}

@Test
public void resolveReflogParent() 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();
git.commit().setMessage("edit file").call();

assertEquals(c1, db.resolve("master@{0}~1"));
}

@Test
public void resolveNonExistingBranch() throws Exception {
Git git = new Git(db);
writeTrashFile("file.txt", "content");
git.add().addFilepattern("file.txt").call();
git.commit().setMessage("create file").call();
assertNull(db.resolve("notabranch@{7}"));
}

@Test
public void resolveNegativeEntryNumber() throws Exception {
Git git = new Git(db);
writeTrashFile("file.txt", "content");
git.add().addFilepattern("file.txt").call();
git.commit().setMessage("create file").call();
try {
db.resolve("master@{-12}");
fail("Exception not thrown");
} catch (RevisionSyntaxException e) {
assertNotNull(e);
}
}

@Test
public void resolveDate() throws Exception {
Git git = new Git(db);
writeTrashFile("file.txt", "content");
git.add().addFilepattern("file.txt").call();
git.commit().setMessage("create file").call();
try {
db.resolve("master@{yesterday}");
fail("Exception not thrown");
} catch (RevisionSyntaxException e) {
assertNotNull(e);
}
}
}

+ 2
- 1
org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties View File

@@ -249,6 +249,7 @@ invalidObject=Invalid {0} {1}:{2}
invalidOldIdSent=invalid old id sent
invalidPacketLineHeader=Invalid packet line header: {0}
invalidPath=Invalid path: {0}
invalidReflogRevision=Invalid reflog revision: {0}
invalidRefName=Invalid ref name: {0}
invalidRemote=Invalid remote: {0}
invalidStageForPath=Invalid stage {0} for path {1}
@@ -366,7 +367,7 @@ receivingObjects=Receiving objects
refAlreadyExists=Ref {0} already exists
refNotResolved=Ref {0} can not be resolved
refUpdateReturnCodeWas=RefUpdate return code was: {0}
reflogsNotYetSupportedByRevisionParser=reflogs not yet supported by revision parser
reflogEntryNotFound=Entry {0} not found in reflog for ''{1}'', only {2} entries exist
remoteConfigHasNoURIAssociated=Remote config "{0}" has no URIs associated
remoteDoesNotHaveSpec=Remote does not have {0} available for fetch.
remoteDoesNotSupportSmartHTTPPush=remote does not support smart HTTP push

+ 2
- 1
org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java View File

@@ -310,6 +310,7 @@ public class JGitText extends TranslationBundle {
/***/ public String invalidPacketLineHeader;
/***/ public String invalidPath;
/***/ public String invalidRemote;
/***/ public String invalidReflogRevision;
/***/ public String invalidRefName;
/***/ public String invalidStageForPath;
/***/ public String invalidTagOption;
@@ -426,7 +427,7 @@ public class JGitText extends TranslationBundle {
/***/ public String refAlreadyExists;
/***/ public String refNotResolved;
/***/ public String refUpdateReturnCodeWas;
/***/ public String reflogsNotYetSupportedByRevisionParser;
/***/ public String reflogEntryNotFound;
/***/ public String remoteConfigHasNoURIAssociated;
/***/ public String remoteDoesNotHaveSpec;
/***/ public String remoteDoesNotSupportSmartHTTPPush;

+ 35
- 5
org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java View File

@@ -51,6 +51,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -78,6 +79,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.ReflogEntry;
import org.eclipse.jgit.storage.file.ReflogReader;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FS;
@@ -524,11 +526,15 @@ public abstract class Repository {
break;
}
}
if (time != null)
throw new RevisionSyntaxException(
JGitText.get().reflogsNotYetSupportedByRevisionParser,
revstr);
i = m - 1;
if (time != null) {
String refName = new String(rev, 0, i);
Ref resolved = getRefDatabase().getRef(refName);
if (resolved == null)
return null;
ref = resolveReflog(rw, resolved, time);
i = m;
} else
i = m - 1;
break;
case ':': {
RevTree tree;
@@ -610,6 +616,30 @@ public abstract class Repository {
return null;
}

private RevCommit resolveReflog(RevWalk rw, Ref ref, String time)
throws IOException {
int number;
try {
number = Integer.parseInt(time);
} catch (NumberFormatException nfe) {
throw new RevisionSyntaxException(MessageFormat.format(
JGitText.get().invalidReflogRevision, time));
}
if (number < 0)
throw new RevisionSyntaxException(MessageFormat.format(
JGitText.get().invalidReflogRevision, time));

ReflogReader reader = new ReflogReader(this, ref.getName());
List<ReflogEntry> entries = reader.getReverseEntries(number + 1);
if (number >= entries.size())
throw new RevisionSyntaxException(MessageFormat.format(
JGitText.get().reflogEntryNotFound,
Integer.valueOf(number), ref.getName(),
Integer.valueOf(entries.size())));

return rw.parseCommit(entries.get(number).getNewId());
}

private ObjectId resolveAbbreviation(final String revstr) throws IOException,
AmbiguousObjectException {
AbbreviatedObjectId id = AbbreviatedObjectId.fromString(revstr);

Loading…
Cancel
Save