From a2d5650b8fc6775cc8684550d205502c70ab8771 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Sun, 20 Feb 2022 12:03:22 +0100 Subject: [PATCH 1/9] DescribeCommand: Add support for --abbrev=0 Setting --abbrev=0 suppresses long format and only shows the closest tag [1]. [1] https://git-scm.com/docs/git-describe#Documentation/git-describe.txt---abbrevltngt Change-Id: Ifcf4d7786dd0f0fb0315d8093fdb54384ed9d5f9 --- .../tst/org/eclipse/jgit/api/DescribeCommandTest.java | 2 ++ org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java | 3 +++ 2 files changed, 5 insertions(+) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java index 205116999..48980ad6e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java @@ -102,6 +102,8 @@ public void testDescribe() throws Exception { assertEquals("alice-t1-2-g3e563c5", describe(c4, "alice*")); assertEquals("bob-t2-1-g3e563c5", describe(c4, "bob*")); assertEquals("bob-t2-1-g3e563c5", describe(c4, "a*", "b*", "c*")); + + assertEquals("bob-t2", describe(c4, false, true, 0)); } else { assertEquals(null, describe(c2)); assertEquals(null, describe(c3)); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java index e572773e4..955d14769 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java @@ -227,6 +227,9 @@ public DescribeCommand setAbbrev(int abbrev) { private String longDescription(Ref tag, int depth, ObjectId tip) throws IOException { + if (abbrev == 0) { + return formatRefName(tag.getName()); + } return String.format("%s-%d-g%s", formatRefName(tag.getName()), //$NON-NLS-1$ Integer.valueOf(depth), w.getObjectReader().abbreviate(tip, abbrev).name()); From 85d8b31cb25e779f2511d96e0dd1a0606512e8b4 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Sun, 20 Feb 2022 12:00:49 +0100 Subject: [PATCH 2/9] Cap describe abbrev option - minimum is 4 [1] - maximum is length of a full ObjectId [1] https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreabbrev Change-Id: I145bde1a218f71b87b8d8260761dd0853770bb76 --- .../eclipse/jgit/api/DescribeCommandTest.java | 18 +++++++++--------- .../org/eclipse/jgit/api/DescribeCommand.java | 12 ++++++++++-- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java index 48980ad6e..ab87fa966 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java @@ -14,7 +14,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import java.io.BufferedWriter; @@ -104,6 +103,10 @@ public void testDescribe() throws Exception { assertEquals("bob-t2-1-g3e563c5", describe(c4, "a*", "b*", "c*")); assertEquals("bob-t2", describe(c4, false, true, 0)); + assertEquals("bob-t2-1-g3e56", describe(c4, false, true, 1)); + assertEquals("bob-t2-1-g3e56", describe(c4, false, true, -10)); + assertEquals("bob-t2-1-g3e563c55927905f21e3bc7c00a3d83a31bf4ed3a", + describe(c4, false, true, 50)); } else { assertEquals(null, describe(c2)); assertEquals(null, describe(c3)); @@ -117,16 +120,13 @@ public void testDescribe() throws Exception { assertEquals("44579ebe7f", describe(c3, false, true, 10)); assertEquals("3e563c5592", describe(c4, false, true, 10)); - assertEquals("3e", describe(c4, false, true, 2)); + assertEquals("3e56", describe(c4, false, true, -10)); + assertEquals("3e56", describe(c4, false, true, 0)); + assertEquals("3e56", describe(c4, false, true, 2)); assertEquals("3e563c55927905f21e3bc7c00a3d83a31bf4ed3a", describe(c4, false, true, 40)); - - assertThrows(StringIndexOutOfBoundsException.class, - () -> describe(c4, false, true, -10)); - assertThrows(StringIndexOutOfBoundsException.class, - () -> describe(c4, false, true, 1)); - assertThrows(StringIndexOutOfBoundsException.class, - () -> describe(c4, false, true, 41)); + assertEquals("3e563c55927905f21e3bc7c00a3d83a31bf4ed3a", + describe(c4, false, true, 42)); } // test default target diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java index 955d14769..2480e2ebd 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java @@ -232,7 +232,13 @@ private String longDescription(Ref tag, int depth, ObjectId tip) } return String.format("%s-%d-g%s", formatRefName(tag.getName()), //$NON-NLS-1$ Integer.valueOf(depth), - w.getObjectReader().abbreviate(tip, abbrev).name()); + w.getObjectReader().abbreviate(tip, getCappedAbbrev()).name()); + } + + private int getCappedAbbrev() { + int len = Math.max(abbrev, 4); + len = Math.min(len, Constants.OBJECT_ID_STRING_LENGTH); + return len; } /** @@ -436,7 +442,9 @@ String describe(ObjectId tip) throws IOException { // if all the nodes are dominated by all the tags, the walk stops if (candidates.isEmpty()) { return always - ? w.getObjectReader().abbreviate(target, abbrev).name() + ? w.getObjectReader() + .abbreviate(target, getCappedAbbrev()) + .name() : null; } From 9c27002c492e29a7f81a97899e779d5778fda796 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Sun, 20 Feb 2022 12:04:11 +0100 Subject: [PATCH 3/9] [pgm] Add describe --abbrev option Change-Id: I8adf2fad21db71b43266d3f274143eee6bc9dce2 --- .../org/eclipse/jgit/pgm/DescribeTest.java | 25 +++++++++++++++++++ .../jgit/pgm/internal/CLIText.properties | 1 + .../src/org/eclipse/jgit/pgm/Describe.java | 6 +++++ 3 files changed, 32 insertions(+) diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java index 4bad73b5b..c78544309 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java @@ -88,6 +88,31 @@ public void testDescribeCommitMatch() throws Exception { execute("git describe --match v1.*")); } + @Test + public void testDescribeCommitMatchAbbrev() throws Exception { + initialCommitAndTag(); + secondCommit(); + assertArrayEquals(new String[] { "v1.0-1-g56f6cebdf3f5", "" }, + execute("git describe --abbrev 12 --match v1.*")); + } + + @Test + public void testDescribeCommitMatchAbbrevMin() throws Exception { + initialCommitAndTag(); + secondCommit(); + assertArrayEquals(new String[] { "v1.0-1-g56f6", "" }, + execute("git describe --abbrev -5 --match v1.*")); + } + + @Test + public void testDescribeCommitMatchAbbrevMax() throws Exception { + initialCommitAndTag(); + secondCommit(); + assertArrayEquals(new String[] { + "v1.0-1-g56f6cebdf3f5ceeecd803365abf0996fb1fa006d", "" }, + execute("git describe --abbrev 50 --match v1.*")); + } + @Test public void testDescribeCommitMatch2() throws Exception { initialCommitAndTag(); diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties index d51daafde..fda0bf6ff 100644 --- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties +++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties @@ -229,6 +229,7 @@ unmergedPaths=Unmerged paths: unsupportedOperation=Unsupported operation: {0} untrackedFiles=Untracked files: updating=Updating {0}..{1} +usage_Abbrev=Instead of using the default number of hexadecimal digits (which will vary according to the number of objects in the repository with a default of 7) of the abbreviated object name, use digits, or as many digits as needed to form a unique object name. An of 0 will suppress long format, only showing the closest tag. usage_Aggressive=This option will cause gc to more aggressively optimize the repository at the expense of taking much more time usage_AlwaysFallback=Show uniquely abbreviated commit object as fallback usage_bareClone=Make a bare Git repository. That is, instead of creating [DIRECTORY] and placing the administrative files in [DIRECTORY]/.git, make the [DIRECTORY] itself the $GIT_DIR. diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java index 8aa119a35..116db037d 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java @@ -44,6 +44,9 @@ class Describe extends TextBuiltin { @Option(name = "--match", usage = "usage_Match", metaVar = "metaVar_pattern") private List patterns = new ArrayList<>(); + @Option(name = "--abbrev", usage = "usage_Abbrev") + private Integer abbrev; + /** {@inheritDoc} */ @Override protected void run() { @@ -57,6 +60,9 @@ protected void run() { cmd.setTags(useTags); cmd.setAlways(always); cmd.setMatch(patterns.toArray(new String[0])); + if (abbrev != null) { + cmd.setAbbrev(abbrev.intValue()); + } String result = null; try { result = cmd.call(); From c543b8ee1a8c2e265c08688ff495933204819828 Mon Sep 17 00:00:00 2001 From: Fabio Ponciroli Date: Wed, 2 Mar 2022 10:03:51 +0100 Subject: [PATCH 4/9] Make precedence more explicit Errorprone was failing the build with: "[OperatorPrecedence]. Use grouping parenthesis to make the operator precedence explicit" Add parentheses to silence it. Change-Id: I81f1f249e38fd2543f5412b3501b0179d0759f55 --- org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConfig.java index 0de270261..c8774d546 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConfig.java @@ -117,7 +117,7 @@ public String toConfigValue() { @Override public boolean matchConfigValue(String in) { return toConfigValue().equalsIgnoreCase(in) - || alias != null && alias.equalsIgnoreCase(in); + || (alias != null && alias.equalsIgnoreCase(in)); } } From 889b82f0e5b2d6dc7ea82eca3ba13598917877f2 Mon Sep 17 00:00:00 2001 From: Fabio Ponciroli Date: Mon, 7 Feb 2022 19:30:01 +0100 Subject: [PATCH 5/9] Remove ignored potentiallyUnclosedCloseable check potentiallyUnclosedCloseable currently is not checked and it creates a warning when compiling with Maven. Change-Id: I0715ead433270937f77f56a19aa203f8d6f5322f --- .../eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java index bacd3ba0a..ab588cb71 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java @@ -269,7 +269,6 @@ public boolean shouldReportEvictedEvent() { assertEquals(1, evicted.get()); } - @SuppressWarnings("resource") @Test public void noConcurrencySerializedReads_oneRepo() throws Exception { InMemoryRepository r1 = createRepoWithBitmap("test"); @@ -384,7 +383,6 @@ public void lowConcurrencyParallelReads_twoReposAndIndex() assertEquals(2, cache.getMissCount()[0]); } - @SuppressWarnings("resource") @Test public void highConcurrencyParallelReads_oneRepo() throws Exception { InMemoryRepository r1 = createRepoWithBitmap("test"); @@ -407,7 +405,6 @@ public void highConcurrencyParallelReads_oneRepo() throws Exception { assertEquals(1, cache.getMissCount()[0]); } - @SuppressWarnings("resource") @Test public void highConcurrencyParallelReads_oneRepoParallelReverseIndex() throws Exception { From 67097f5de497859216576144ab85e3e4b49503fb Mon Sep 17 00:00:00 2001 From: David Ostrovsky Date: Wed, 29 Dec 2021 21:18:52 +0100 Subject: [PATCH 6/9] PersonIdent: Add ctors that accept Instant in addition to Date Error Prone is flagging Date-API as obsolete and recommends to migrate to Instant and LocalDate. Given that more JGit users starting to migrate to new Time API, offer ctors that accept Instant type and also add new getter that returns when attribute as Instant type. Change-Id: I64a36bf40f191495c6889c1dff314ede06848880 --- .../jgit/lib/T0001_PersonIdentTest.java | 30 ++++++++++ .../src/org/eclipse/jgit/lib/PersonIdent.java | 57 +++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java index e9bab7c4a..367084510 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java @@ -13,6 +13,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.time.Instant; +import java.time.ZoneId; import java.util.Date; import java.util.TimeZone; @@ -42,6 +44,34 @@ public void test002_NewIdent() { p.toExternalString()); } + @Test + public void testNewIdentInstant() { + PersonIdent p = new PersonIdent("A U Thor", "author@example.com", + Instant.ofEpochMilli(1142878501000L), + ZoneId.of("America/New_York")); + assertEquals("A U Thor", p.getName()); + assertEquals("author@example.com", p.getEmailAddress()); + assertEquals(Instant.ofEpochMilli(1142878501000L), + p.getWhenAsInstant()); + assertEquals("A U Thor 1142878501 -0500", + p.toExternalString()); + assertEquals(ZoneId.of("GMT-05:00"), p.getZoneId()); + } + + @Test + public void testNewIdentInstant2() { + final PersonIdent p = new PersonIdent("A U Thor", "author@example.com", + Instant.ofEpochMilli(1142878501000L), + ZoneId.of("Asia/Kolkata")); + assertEquals("A U Thor", p.getName()); + assertEquals("author@example.com", p.getEmailAddress()); + assertEquals(Instant.ofEpochMilli(1142878501000L), + p.getWhenAsInstant()); + assertEquals("A U Thor 1142878501 +0530", + p.toExternalString()); + assertEquals(ZoneId.of("GMT+05:30"), p.getZoneId()); + } + @SuppressWarnings("unused") @Test(expected = IllegalArgumentException.class) public void nullForNameShouldThrowIllegalArgumentException() { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java index 428a6b959..93710299b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java @@ -14,6 +14,8 @@ import java.io.Serializable; import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.ZoneId; import java.util.Date; import java.util.Locale; import java.util.TimeZone; @@ -205,6 +207,20 @@ public PersonIdent(PersonIdent pi, Date aWhen) { this(pi.getName(), pi.getEmailAddress(), aWhen.getTime(), pi.tzOffset); } + /** + * Copy a {@link org.eclipse.jgit.lib.PersonIdent}, but alter the clone's + * time stamp + * + * @param pi + * original {@link org.eclipse.jgit.lib.PersonIdent} + * @param aWhen + * local time as Instant + * @since 6.1 + */ + public PersonIdent(PersonIdent pi, Instant aWhen) { + this(pi.getName(), pi.getEmailAddress(), aWhen.toEpochMilli(), pi.tzOffset); + } + /** * Construct a PersonIdent from simple data * @@ -221,6 +237,27 @@ public PersonIdent(final String aName, final String aEmailAddress, .getTime()) / (60 * 1000)); } + /** + * Construct a PersonIdent from simple data + * + * @param aName + * a {@link java.lang.String} object. + * @param aEmailAddress + * a {@link java.lang.String} object. + * @param aWhen + * local time stamp + * @param zoneId + * time zone id + * @since 6.1 + */ + public PersonIdent(final String aName, String aEmailAddress, Instant aWhen, + ZoneId zoneId) { + this(aName, aEmailAddress, aWhen.toEpochMilli(), + TimeZone.getTimeZone(zoneId) + .getOffset(aWhen + .toEpochMilli()) / (60 * 1000)); + } + /** * Copy a PersonIdent, but alter the clone's time stamp * @@ -303,6 +340,16 @@ public Date getWhen() { return new Date(when); } + /** + * Get when attribute as instant + * + * @return timestamp + * @since 6.1 + */ + public Instant getWhenAsInstant() { + return Instant.ofEpochMilli(when); + } + /** * Get this person's declared time zone * @@ -312,6 +359,16 @@ public TimeZone getTimeZone() { return getTimeZone(tzOffset); } + /** + * Get the time zone id + * + * @return the time zone id + * @since 6.1 + */ + public ZoneId getZoneId() { + return getTimeZone().toZoneId(); + } + /** * Get this person's declared time zone as minutes east of UTC. * From 9284ed5db736b4d974e0e4bf781e4001c7c415e7 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Mon, 7 Feb 2022 23:12:34 +0100 Subject: [PATCH 7/9] Remove odd prefix of PersonIdent test class Change-Id: I05ede49902527c435691fb2c0f0d4da7ba077b7a --- .../lib/{T0001_PersonIdentTest.java => PersonIdentTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/{T0001_PersonIdentTest.java => PersonIdentTest.java} (99%) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PersonIdentTest.java similarity index 99% rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PersonIdentTest.java index 367084510..97da1757e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PersonIdentTest.java @@ -20,7 +20,7 @@ import org.junit.Test; -public class T0001_PersonIdentTest { +public class PersonIdentTest { @Test public void test001_NewIdent() { From 9244c07d73968f668e7579a6c8ff626982229b3f Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Tue, 22 Feb 2022 01:20:07 +0100 Subject: [PATCH 8/9] Add a typed config getter for integers confined to a range Use Integer#MIN_VALUE to denote unset option. Change-Id: I4d65f2434013111f25520c0ed2b9a9dc8123c6cf --- org.eclipse.jgit/.settings/.api_filters | 14 ++++++++ .../eclipse/jgit/internal/JGitText.properties | 2 ++ .../org/eclipse/jgit/internal/JGitText.java | 2 ++ .../jgit/lib/DefaultTypedConfigGetter.java | 20 +++++++++++ .../eclipse/jgit/lib/TypedConfigGetter.java | 33 +++++++++++++++++++ 5 files changed, 71 insertions(+) diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index 792a0c91c..88a712e7b 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -9,6 +9,20 @@ + + + + + + + + + + + + + + diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 31579c98a..6e0d8f562 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -354,6 +354,8 @@ initFailedNonBareRepoSameDirs=When initializing a non-bare repo with directory { inMemoryBufferLimitExceeded=In-memory buffer limit exceeded inputDidntMatchLength=Input did not match supplied length. {0} bytes are missing. inputStreamMustSupportMark=InputStream must support mark() +integerValueNotInRange=Integer value {0}.{1} = {2} not in range {3}..{4} +integerValueNotInRangeSubSection=Integer value {0}.{1}.{2} = {3} not in range {4}..{5} integerValueOutOfRange=Integer value {0}.{1} out of range internalRevisionError=internal revision error internalServerError=internal server error diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index 58615b44d..9623346b0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -382,6 +382,8 @@ public static JGitText get() { /***/ public String inMemoryBufferLimitExceeded; /***/ public String inputDidntMatchLength; /***/ public String inputStreamMustSupportMark; + /***/ public String integerValueNotInRange; + /***/ public String integerValueNotInRangeSubSection; /***/ public String integerValueOutOfRange; /***/ public String internalRevisionError; /***/ public String internalServerError; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java index 9f96bce25..86409403b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java @@ -118,6 +118,26 @@ public int getInt(Config config, String section, String subsection, .format(JGitText.get().integerValueOutOfRange, section, name)); } + /** {@inheritDoc} */ + @Override + public int getIntInRange(Config config, String section, String subsection, + String name, int minValue, int maxValue, int defaultValue) { + int val = getInt(config, section, subsection, name, defaultValue); + if ((val >= minValue && val <= maxValue) || val == UNSET_INT) { + return val; + } + if (subsection == null) { + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().integerValueNotInRange, section, name, + Integer.valueOf(val), Integer.valueOf(minValue), + Integer.valueOf(maxValue))); + } + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().integerValueNotInRangeSubSection, section, + subsection, name, Integer.valueOf(val), + Integer.valueOf(minValue), Integer.valueOf(maxValue))); + } + /** {@inheritDoc} */ @Override public long getLong(Config config, String section, String subsection, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java index 0f2f6cff8..c4eb8f10d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java @@ -28,6 +28,13 @@ */ public interface TypedConfigGetter { + /** + * Use {@code Integer#MIN_VALUE} as unset int value + * + * @since 6.1 + */ + public static final int UNSET_INT = Integer.MIN_VALUE; + /** * Get a boolean value from a git {@link Config}. * @@ -86,6 +93,32 @@ > T getEnum(Config config, T[] all, String section, int getInt(Config config, String section, String subsection, String name, int defaultValue); + /** + * Obtain an integer value from a git {@link Config} which must be in given + * range. + * + * @param config + * to get the value from + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @param minValue + * minimal value + * @param maxValue + * maximum value + * @param defaultValue + * default value to return if no value was present. Use + * {@code #UNSET_INT} to set the default to unset. + * @return an integer value from the configuration, or defaultValue. + * {@code #UNSET_INT} if unset. + * @since 6.1 + */ + int getIntInRange(Config config, String section, String subsection, + String name, int minValue, int maxValue, int defaultValue); + /** * Obtain a long value from a git {@link Config}. * From 6f175ea6c46488d7d301a74ccc87d7472c314c1a Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Mon, 21 Feb 2022 02:29:27 +0100 Subject: [PATCH 9/9] Describe: add support for core.abbrev config option If core.abbrev is unset or "auto" estimate abbreviation length like C git does: - Estimate repository's object count by only considering packed objects, round up to next power of 2 - With the order of 2^len objects, we expect a collision at 2^(len/2). But we also care about hex chars, not bits, and there are 4 bits per hex. So all together we need to divide by 2; but we also want to round odd numbers up, hence adding one before dividing. - For small repos use at least 7 hexdigits - If object database fails to determine object count use 7 hexdigits as fallback If it is set to "no" do not abbreviate object-ids. Otherwise set it to the configured value capped to the range between 4 and length of an unabbreviated object-id. Change-Id: I425f9724b69813dbb57872466bf2d2e1d6dc72c6 --- .../eclipse/jgit/lib/AbbrevConfigTest.java | 128 +++++++++++++++ org.eclipse.jgit/.settings/.api_filters | 16 ++ .../eclipse/jgit/internal/JGitText.properties | 1 + .../org/eclipse/jgit/api/DescribeCommand.java | 28 ++-- .../org/eclipse/jgit/internal/JGitText.java | 1 + .../storage/dfs/InMemoryRepository.java | 9 ++ .../storage/file/CachedObjectDirectory.java | 13 ++ .../storage/file/ObjectDirectory.java | 14 ++ .../org/eclipse/jgit/lib/AbbrevConfig.java | 150 ++++++++++++++++++ .../src/org/eclipse/jgit/lib/Config.java | 48 ++++++ .../org/eclipse/jgit/lib/ConfigConstants.java | 7 + .../org/eclipse/jgit/lib/ObjectDatabase.java | 10 ++ 12 files changed, 413 insertions(+), 12 deletions(-) create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbrevConfigTest.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbrevConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbrevConfigTest.java new file mode 100644 index 000000000..96ace08dd --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbrevConfigTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2022, Matthias Sohn and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.lib; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import java.io.IOException; + +import org.eclipse.jgit.api.errors.InvalidConfigurationException; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.junit.Test; + +public class AbbrevConfigTest extends RepositoryTestCase { + + @Test + public void testDefault() throws Exception { + assertEquals(7, testCoreAbbrev(null)); + } + + @Test + public void testAuto() throws Exception { + assertEquals(7, testCoreAbbrev("auto")); + } + + @Test + public void testNo() throws Exception { + assertEquals(40, testCoreAbbrev("no")); + } + + @Test + public void testValidMin() throws Exception { + assertEquals(4, testCoreAbbrev("4")); + } + + @Test + public void testValid() throws Exception { + assertEquals(22, testCoreAbbrev("22")); + } + + @Test + public void testValidMax() throws Exception { + assertEquals(40, testCoreAbbrev("40")); + } + + @Test + public void testInvalid() { + assertThrows(InvalidConfigurationException.class, + () -> testCoreAbbrev("foo")); + } + + @Test + public void testInvalid2() { + assertThrows(InvalidConfigurationException.class, + () -> testCoreAbbrev("2k")); + } + + @Test + public void testInvalidNegative() { + assertThrows(InvalidConfigurationException.class, + () -> testCoreAbbrev("-1000")); + } + + @Test + public void testInvalidBelowRange() { + assertThrows(InvalidConfigurationException.class, + () -> testCoreAbbrev("3")); + } + + @Test + public void testInvalidBelowRange2() { + assertThrows(InvalidConfigurationException.class, + () -> testCoreAbbrev("-1")); + } + + @Test + public void testInvalidAboveRange() { + assertThrows(InvalidConfigurationException.class, + () -> testCoreAbbrev("41")); + } + + @Test + public void testInvalidAboveRange2() { + assertThrows(InvalidConfigurationException.class, + () -> testCoreAbbrev("100000")); + } + + @Test + public void testToStringNo() + throws InvalidConfigurationException, IOException { + assertEquals("40", setCoreAbbrev("no").toString()); + } + + @Test + public void testToString() + throws InvalidConfigurationException, IOException { + assertEquals("7", setCoreAbbrev("auto").toString()); + } + + @Test + public void testToString12() + throws InvalidConfigurationException, IOException { + assertEquals("12", setCoreAbbrev("12").toString()); + } + + private int testCoreAbbrev(String value) + throws InvalidConfigurationException, IOException { + return setCoreAbbrev(value).get(); + } + + private AbbrevConfig setCoreAbbrev(String value) + throws IOException, InvalidConfigurationException { + FileBasedConfig config = db.getConfig(); + config.setString(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_ABBREV, value); + config.save(); + return AbbrevConfig.parseFromConfig(db); + } + +} diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index 88a712e7b..e026e31dc 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -23,6 +23,22 @@ + + + + + + + + + + + + + + + + diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 6e0d8f562..e6f4e65e7 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -366,6 +366,7 @@ invalidAncestryLength=Invalid ancestry length invalidBooleanValue=Invalid boolean value: {0}.{1}={2} invalidChannel=Invalid channel {0} invalidCommitParentNumber=Invalid commit parent number +invalidCoreAbbrev=Invalid value {0} of option core.abbrev invalidDepth=Invalid depth: {0} invalidEncoding=Invalid encoding from git config i18n.commitEncoding: {0} invalidEncryption=Invalid encryption diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java index 2480e2ebd..805a88639 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java @@ -9,9 +9,9 @@ */ package org.eclipse.jgit.api; -import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; import static org.eclipse.jgit.lib.Constants.R_REFS; import static org.eclipse.jgit.lib.Constants.R_TAGS; +import static org.eclipse.jgit.lib.TypedConfigGetter.UNSET_INT; import java.io.IOException; import java.text.MessageFormat; @@ -34,6 +34,7 @@ import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.fnmatch.FileNameMatcher; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.AbbrevConfig; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; @@ -92,7 +93,7 @@ public class DescribeCommand extends GitCommand { /** * The prefix length to use when abbreviating a commit hash. */ - private int abbrev = OBJECT_ID_ABBREV_STRING_LENGTH; + private int abbrev = UNSET_INT; /** * Constructor for DescribeCommand. @@ -216,12 +217,17 @@ public DescribeCommand setAlways(boolean always) { * * @param abbrev * minimum length of the abbreviated string. Must be in the range - * [2, {@value Constants#OBJECT_ID_STRING_LENGTH}]. + * [{@value AbbrevConfig#MIN_ABBREV}, + * {@value Constants#OBJECT_ID_STRING_LENGTH}]. * @return {@code this} * @since 6.1 */ public DescribeCommand setAbbrev(int abbrev) { - this.abbrev = abbrev; + if (abbrev == 0) { + this.abbrev = 0; + } else { + this.abbrev = AbbrevConfig.capAbbrev(abbrev); + } return this; } @@ -232,13 +238,7 @@ private String longDescription(Ref tag, int depth, ObjectId tip) } return String.format("%s-%d-g%s", formatRefName(tag.getName()), //$NON-NLS-1$ Integer.valueOf(depth), - w.getObjectReader().abbreviate(tip, getCappedAbbrev()).name()); - } - - private int getCappedAbbrev() { - int len = Math.max(abbrev, 4); - len = Math.min(len, Constants.OBJECT_ID_STRING_LENGTH); - return len; + w.getObjectReader().abbreviate(tip, abbrev).name()); } /** @@ -330,6 +330,9 @@ public String call() throws GitAPIException { if (target == null) { setTarget(Constants.HEAD); } + if (abbrev == UNSET_INT) { + abbrev = AbbrevConfig.parseFromConfig(repo).get(); + } Collection tagList = repo.getRefDatabase() .getRefsByPrefix(useAll ? R_REFS : R_TAGS); @@ -443,7 +446,8 @@ String describe(ObjectId tip) throws IOException { if (candidates.isEmpty()) { return always ? w.getObjectReader() - .abbreviate(target, getCappedAbbrev()) + .abbreviate(target, + AbbrevConfig.capAbbrev(abbrev)) .name() : null; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index 9623346b0..16b3f372e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -394,6 +394,7 @@ public static JGitText get() { /***/ public String invalidBooleanValue; /***/ public String invalidChannel; /***/ public String invalidCommitParentNumber; + /***/ public String invalidCoreAbbrev; /***/ public String invalidDepth; /***/ public String invalidEncoding; /***/ public String invalidEncryption; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java index 5b6894da9..99da22239 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java @@ -165,6 +165,15 @@ public void flush() { } }; } + + @Override + public long getApproximateObjectCount() { + long count = 0; + for (DfsPackDescription p : packs) { + count += p.getObjectCount(); + } + return count; + } } private static class MemPack extends DfsPackDescription { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java index 7dedeb57a..094fdc155 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java @@ -263,4 +263,17 @@ private static class UnpackedObjectId extends ObjectIdOwnerMap.Entry { private AlternateHandle.Id getAlternateId() { return wrapped.getAlternateId(); } + + @Override + public long getApproximateObjectCount() { + long count = 0; + for (Pack p : getPacks()) { + try { + count += p.getObjectCount(); + } catch (IOException e) { + return -1; + } + } + return count; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java index 627facca0..06c8cad3a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java @@ -212,6 +212,20 @@ public Collection getPacks() { return packed.getPacks(); } + /** {@inheritDoc} */ + @Override + public long getApproximateObjectCount() { + long count = 0; + for (Pack p : getPacks()) { + try { + count += p.getIndex().getObjectCount(); + } catch (IOException e) { + return -1; + } + } + return count; + } + /** * {@inheritDoc} *

diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java new file mode 100644 index 000000000..9109cfd76 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2022, Matthias Sohn and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.lib; + +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; +import static org.eclipse.jgit.lib.TypedConfigGetter.UNSET_INT; + +import java.text.MessageFormat; + +import org.eclipse.jgit.api.errors.InvalidConfigurationException; +import org.eclipse.jgit.internal.JGitText; + +/** + * Git configuration option + * core.abbrev + * + * @since 6.1 + */ +public final class AbbrevConfig { + private static final String VALUE_NO = "no"; //$NON-NLS-1$ + + private static final String VALUE_AUTO = "auto"; //$NON-NLS-1$ + + /** + * The minimum value of abbrev + */ + public static final int MIN_ABBREV = 4; + + /** + * Cap configured core.abbrev to range between minimum of 4 and number of + * hex-digits of a full object id. + * + * @param len + * configured number of hex-digits to abbreviate object ids to + * @return core.abbrev capped to range between minimum of 4 and number of + * hex-digits of a full object id + */ + public static int capAbbrev(int len) { + return Math.min(Math.max(MIN_ABBREV, len), + Constants.OBJECT_ID_STRING_LENGTH); + } + + /** + * No abbreviation + */ + public final static AbbrevConfig NO = new AbbrevConfig( + Constants.OBJECT_ID_STRING_LENGTH); + + /** + * Parse string value of core.abbrev git option for a given repository + * + * @param repo + * repository + * @return the parsed AbbrevConfig + * @throws InvalidConfigurationException + * if value of core.abbrev is invalid + */ + public static AbbrevConfig parseFromConfig(Repository repo) + throws InvalidConfigurationException { + Config config = repo.getConfig(); + String value = config.getString(ConfigConstants.CONFIG_CORE_SECTION, + null, ConfigConstants.CONFIG_KEY_ABBREV); + if (value == null || value.equalsIgnoreCase(VALUE_AUTO)) { + return auto(repo); + } + if (value.equalsIgnoreCase(VALUE_NO)) { + return NO; + } + try { + int len = config.getIntInRange(ConfigConstants.CONFIG_CORE_SECTION, + ConfigConstants.CONFIG_KEY_ABBREV, MIN_ABBREV, + Constants.OBJECT_ID_STRING_LENGTH, UNSET_INT); + if (len == UNSET_INT) { + // Unset was checked above. If we get UNSET_INT here, then + // either the value was UNSET_INT, or it was an invalid value + // (not an integer, or out of range), and EGit's + // ReportingTypedGetter caught the exception and has logged a + // warning. In either case we should fall back to some sane + // default. + len = OBJECT_ID_ABBREV_STRING_LENGTH; + } + return new AbbrevConfig(len); + } catch (IllegalArgumentException e) { + throw new InvalidConfigurationException(MessageFormat + .format(JGitText.get().invalidCoreAbbrev, value), e); + } + } + + /** + * An appropriate value is computed based on the approximate number of + * packed objects in a repository, which hopefully is enough for abbreviated + * object names to stay unique for some time. + * + * @param repo + * @return appropriate value computed based on the approximate number of + * packed objects in a repository + */ + private static AbbrevConfig auto(Repository repo) { + long count = repo.getObjectDatabase().getApproximateObjectCount(); + if (count == -1) { + return new AbbrevConfig(OBJECT_ID_ABBREV_STRING_LENGTH); + } + // find msb, round to next power of 2 + int len = 63 - Long.numberOfLeadingZeros(count) + 1; + // With the order of 2^len objects, we expect a collision at + // 2^(len/2). But we also care about hex chars, not bits, and + // there are 4 bits per hex. So all together we need to divide + // by 2; but we also want to round odd numbers up, hence adding + // one before dividing. + len = (len + 1) / 2; + // for small repos use at least fallback length + return new AbbrevConfig(Math.max(len, OBJECT_ID_ABBREV_STRING_LENGTH)); + } + + /** + * All other possible abbreviation lengths. Valid range 4 to number of + * hex-digits of an unabbreviated object id (40 for SHA1 object ids, jgit + * doesn't support SHA256 yet). + */ + private int abbrev; + + /** + * @param abbrev + */ + private AbbrevConfig(int abbrev) { + this.abbrev = capAbbrev(abbrev); + } + + /** + * Get the configured abbreviation length for object ids. + * + * @return the configured abbreviation length for object ids + */ + public int get() { + return abbrev; + } + + @Override + public String toString() { + return Integer.toString(abbrev); + } +} \ No newline at end of file diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java index 1ce3e312e..d1d66d280 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java @@ -277,6 +277,54 @@ public int getInt(final String section, String subsection, defaultValue); } + /** + * Obtain an integer value from the configuration which must be inside given + * range. + * + * @param section + * section the key is grouped within. + * @param name + * name of the key to get. + * @param minValue + * minimum value + * @param maxValue + * maximum value + * @param defaultValue + * default value to return if no value was present. + * @return an integer value from the configuration, or defaultValue. + * @since 6.1 + */ + public int getIntInRange(String section, String name, int minValue, + int maxValue, int defaultValue) { + return typedGetter.getIntInRange(this, section, null, name, minValue, + maxValue, defaultValue); + } + + /** + * Obtain an integer value from the configuration which must be inside given + * range. + * + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @param minValue + * minimum value + * @param maxValue + * maximum value + * @param defaultValue + * default value to return if no value was present. + * @return an integer value from the configuration, or defaultValue. + * @since 6.1 + */ + public int getIntInRange(String section, String subsection, String name, + int minValue, int maxValue, int defaultValue) { + return typedGetter.getIntInRange(this, section, subsection, name, + minValue, maxValue, defaultValue); + } + /** * Obtain an integer value from the configuration. * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java index 42d8aa544..80d720ae4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -836,4 +836,11 @@ public final class ConfigConstants { */ public static final String CONFIG_KEY_DEFAULT = "default"; + /** + * The "abbrev" key + * + * @since 6.1 + */ + public static final String CONFIG_KEY_ABBREV = "abbrev"; + } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java index 04262c07a..70009cba3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java @@ -155,4 +155,14 @@ public ObjectLoader open(AnyObjectId objectId, int typeHint) public ObjectDatabase newCachedDatabase() { return this; } + + /** + * Get a quick, rough count of objects in this repository. Ignores loose + * objects. Returns {@code -1} if an exception occurs. + * + * @return quick, rough count of objects in this repository, {@code -1} if + * an exception occurs + * @since 6.1 + */ + public abstract long getApproximateObjectCount(); }