Browse Source

Fix git-describe tie-breakers

Correct behaviour as git 1.7.1.1 is to resolve tie-breakers to choose
the most recent tag.

https://github.com/git/git/blob/master/Documentation/RelNotes/1.7.1.1.txt:
* "git describe" did not tie-break tags that point at the same commit
   correctly; newer ones are preferred by paying attention to the
   tagger date now.

Bug: 538610
Change-Id: Ib0b2a301997bb7f75935baf7005473f4de952a64
Signed-off-by: Håvard Wall <haavardw@gmail.com>
stable-4.11
Håvard Wall 6 years ago
parent
commit
f9de917547
  1. 43
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
  2. 23
      org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java

43
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java

@ -44,6 +44,7 @@ package org.eclipse.jgit.api;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
@ -134,24 +135,48 @@ public class DescribeCommandTest extends RepositoryTestCase {
public void testDescribeMultiMatch() throws Exception { public void testDescribeMultiMatch() throws Exception {
ObjectId c1 = modify("aaa"); ObjectId c1 = modify("aaa");
tag("v1.0.0"); tag("v1.0.0");
tick();
tag("v1.0.1");
tick();
tag("v1.1.0");
tick();
tag("v1.1.1"); tag("v1.1.1");
ObjectId c2 = modify("bbb"); ObjectId c2 = modify("bbb");
// Ensure that if we're interested in any tags, we get the first match as per Git behaviour // Ensure that if we're interested in any tags, we get the most recent tag
assertEquals("v1.0.0", describe(c1)); // as per Git behaviour since 1.7.1.1
assertEquals("v1.0.0-1-g3747db3", describe(c2)); if (useAnnotatedTags) {
assertEquals("v1.1.1", describe(c1));
assertEquals("v1.1.1-1-gb89dead", describe(c2));
// Ensure that if we're only interested in one of multiple tags, we get the right match // Ensure that if we're only interested in one of multiple tags, we get the right match
assertEquals("v1.0.0", describe(c1, "v1.0*")); assertEquals("v1.0.1", describe(c1, "v1.0*"));
assertEquals("v1.1.1", describe(c1, "v1.1*")); assertEquals("v1.1.1", describe(c1, "v1.1*"));
assertEquals("v1.0.0-1-g3747db3", describe(c2, "v1.0*")); assertEquals("v1.0.1-1-gb89dead", describe(c2, "v1.0*"));
assertEquals("v1.1.1-1-g3747db3", describe(c2, "v1.1*")); assertEquals("v1.1.1-1-gb89dead", describe(c2, "v1.1*"));
// Ensure that ordering of match precedence is preserved as per Git behaviour // Ensure that ordering of match precedence is preserved as per Git behaviour
assertEquals("v1.0.0", describe(c1, "v1.0*", "v1.1*")); assertEquals("v1.0.1", describe(c1, "v1.0*", "v1.1*"));
assertEquals("v1.1.1", describe(c1, "v1.1*", "v1.0*")); assertEquals("v1.1.1", describe(c1, "v1.1*", "v1.0*"));
assertEquals("v1.0.0-1-g3747db3", describe(c2, "v1.0*", "v1.1*")); assertEquals("v1.0.1-1-gb89dead", describe(c2, "v1.0*", "v1.1*"));
assertEquals("v1.1.1-1-g3747db3", describe(c2, "v1.1*", "v1.0*")); assertEquals("v1.1.1-1-gb89dead", describe(c2, "v1.1*", "v1.0*"));
} else {
// no timestamps so no guarantees on which tag is chosen
assertNotNull(describe(c1));
assertNotNull(describe(c2));
assertNotNull(describe(c1, "v1.0*"));
assertNotNull(describe(c1, "v1.1*"));
assertNotNull(describe(c2, "v1.0*"));
assertNotNull(describe(c2, "v1.1*"));
// Ensure that ordering of match precedence is preserved as per Git behaviour
assertNotNull(describe(c1, "v1.0*", "v1.1*"));
assertNotNull(describe(c1, "v1.1*", "v1.0*"));
assertNotNull(describe(c2, "v1.0*", "v1.1*"));
assertNotNull(describe(c2, "v1.1*", "v1.0*"));
}
} }
/** /**

23
org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java

@ -50,6 +50,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -71,6 +72,7 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag; import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevFlagSet; import org.eclipse.jgit.revwalk.RevFlagSet;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
/** /**
@ -203,11 +205,29 @@ public class DescribeCommand extends GitCommand<String> {
return this; return this;
} }
private final Comparator<Ref> TAG_TIE_BREAKER = new Comparator<Ref>() {
@Override
public int compare(Ref o1, Ref o2) {
try {
return tagDate(o2).compareTo(tagDate(o1));
} catch (IOException e) {
return 0;
}
}
private Date tagDate(Ref tag) throws IOException {
RevTag t = w.parseTag(tag.getObjectId());
w.parseBody(t);
return t.getTaggerIdent().getWhen();
}
};
private Optional<Ref> getBestMatch(List<Ref> tags) { private Optional<Ref> getBestMatch(List<Ref> tags) {
if (tags == null || tags.size() == 0) { if (tags == null || tags.size() == 0) {
return Optional.empty(); return Optional.empty();
} else if (matchers.size() == 0) { } else if (matchers.size() == 0) {
// No matchers, simply return the first tag entry Collections.sort(tags, TAG_TIE_BREAKER);
return Optional.of(tags.get(0)); return Optional.of(tags.get(0));
} else { } else {
// Find the first tag that matches one of the matchers; precedence according to matcher definition order // Find the first tag that matches one of the matchers; precedence according to matcher definition order
@ -215,6 +235,7 @@ public class DescribeCommand extends GitCommand<String> {
Optional<Ref> match = tags.stream() Optional<Ref> match = tags.stream()
.filter(tag -> matcher.matches(tag.getName(), false, .filter(tag -> matcher.matches(tag.getName(), false,
false)) false))
.sorted(TAG_TIE_BREAKER)
.findFirst(); .findFirst();
if (match.isPresent()) { if (match.isPresent()) {
return match; return match;

Loading…
Cancel
Save